亲宝软件园·资讯

展开

C++内存

一个热爱学习的深度渣渣 人气:0

一、内存基础

1、内存分布

通过下面一张图看看C++的内存分布:

栈区:由编译器自动分配与释放,存放为程序运行时函数分配的局部变量、函数参数;栈内存分配运算内置于处理器的指令集中,效率很高,但是分配内存的容量有限;

堆区:由newmalloc分配的内存块,释放由应用程序控制,不需要编译器释放;如果程序员没有对该内存进行释放,程序结束后系统自动回收,堆的地方比栈大很多;

静态区:存放的是static的静态变量和一些全局变量,特点是只读、大小固定;静态变量和全局变量的存储期是一起的,一旦静态区的内存被分配,要一直等到程序全部结束后才释放;

2、栈区与堆区的区别

1、分配方式不同:栈区系统分配系统回收;堆区由程序员手动申请,需要求程序员自行回收,如果没有回收,系统在程序结束后会进行回收,这种情况会造成内存泄漏;

2、生命周期不同:栈区生命周期是系统分配到系统回收,也就是在大括号内;堆区是从申请到释放;

3、效率不同:主要原因是地址空间是否连续,栈区地址空间是连续的,效率会高一些;堆区地址空间不连续,需要遍历链表才能找到最近的地址,效率会低一些;

4、内存碎片:堆区容易产生内存碎片,栈区不会;

5、生长方向不同:栈区申请空间的地址(表示地址的八个十六进制数)是从大到小的,堆区申请空间地址是从小到大的。栈区是先进后出的原则,类比栈结构的特点;

注意点:申请的空间是在堆区,变量本身是在栈区!

二、内存分配

1、内存分配方式

可操作的内存分配:

不可操作的内存分配:

内核区、代码区、局部变量的分配也属于系统分配;

2、new的用法

C++中通常使用newdelete来构造和销毁对象;

使用new创建对象,返回的是对象的首地址,需要用指针接收:

int *y = new int(2);
std::cout << *y << std::endl;

对象的构建和销毁分为两步:分配内存、所分配内存上构造对象(销毁与之类似);

new的几种常见形式:

3、delete用法

根据分配的是单一对象还是数组,采用相应的方式销毁;

int *y = new int[3];
delete[] y;

不能delete一个非new返回的内存(也就是栈内存);
delete nullptr是可被允许的;
同一块内存不能delete多次;

4、new与malloc的区别

  new不需要指定分配多大,malloc使用的时候必须指定大小;new的底层实现就是malloc,两者都必须释放内存,不否则容易造成野指针或内存泄漏。需要注意一点,释放内存后需设置相关指针为空指针;

总结:

5、内存泄漏

是指由于疏忽或错误造成程序未能释放掉不再使用的内存的情况,内存泄漏并非指内存在物理上的小时,而是应用程序分配某段内存后,由于设计错误,失去该段内存的控制从而造成内存浪费;

可能的原因:

三、内存拓展

1、内存概念

  计算机重要部件之一,是外存与CPU进行沟通的桥梁。计算机所有程序都是在内存运行的,因此内存的性能对计算机的影响非常大。内存也称为内存储器和主存储器,作用是暂时存放CPU的运算数据,以及与硬盘等外部存储器交换的数据;

寻址空间:保存内存地址的多少,通常我们说的4G内存,就表示计算机能保存2的32次方个地址,也就是能找到这些地址上的二进制信息;

寻址能力:每个地址里能存多少个bit,现在的计算机大多数是16位机器了;

2、虚拟内存

使得系统运行实际的内存空间比想象的大得多,虚拟内存是可以远大于物理内存的,同时主要为了使程序运行的时候可以不限制于只访问内存大小,可以通过虚拟内存地址去访问磁盘空间;

每一个进程虚拟内存都是独立的,独立的享有计算机的内存。虚拟内存地址的大小是与地址总线位数相关,物理内存地址的大小是与物理内存条的容量与磁盘容量相关。

四、思考

1、代码中的b属于栈区还是堆区?

void fun()
{
 int *b = new int[14];
}

b是在栈区的变量,由于b是一个局部变量,随着函数域 的结束被释放,不需要程序员自行释放,尽管b使用new进行初始化,还是可以认为分配在栈区;

总结:

本次系统的从内存的基础概念到内存分配进行了讲解,内存是我们开发中最重要的一部分,往往逻辑上的错误就会造成内存泄漏,导致程序无法运行。或者一些分配内存的方式不够细心,也会造成冗余内存的使用。在目前的很多嵌入式板子上,针对内存的接口是必备的,往往也都是基于malloc修改;
还有一点需要注意,不管任何机器上运行程序,操作的都是虚拟内存,内部通过页表定位到对应的物理内存。关于硬件方面的本质,如果做嵌入式端的话需要深入研究。

加载全部内容

相关教程
猜你喜欢
用户评论