C++ 内存分配
0.
学习C++,C#,Java都离不开理解内存分配理论。如果不能理解内存是如何分配的,就需要记住很多复杂而且拗口的规则。如果花一点点时间理解了内存如何分配,那么就可以不用死记硬背那些让人摸不着头脑的规则了。
在尚学堂马士兵老师的视频里面介绍了JAVA内存分配的规则。现在我们来学习一下,C++的内存分配规则。
1. 基本认识
我们大部分程序员写的程序都是跑在跑在操作系统至上的。操作系统会给程序一些内存空间。C++程序会把这些空间分为若干个区域:
1. 代码区域:code area
2. 全局数据区: data area
3. 堆: heap area
4. 栈: stack area
5. 文字常量区: coment
下面我们来分别讨论:
1. code area: 存储函数的二进制代码。
2. data area: static变量和定义在函数外的全局变量都是在data area里开辟空间去存储的。未初始化的全局变量和静态变量存储在bbs区。在vs2012中的实验表明,static变量如果不手动初始化的话编译可以通过,但是,链接的时候会报错。初始化的方式是在main函数之外,是用形如, int class::member = 0; 。
3. heap area: 堆,可以看做是一个资源池,我们可以从资源池里面拿东西,用完了再放回去。我们使用malloc, calloc, realloc这些申请内存,申请到的内存就是从堆上获取的。堆可以申请的空间是很大的。经过试验,在vs2012下,一个win32程序可以申请的空间是2G,因为32位的寻址空间只有2G。频繁的malloc和free很可能产生内存碎片(类似磁盘碎片)。当用户申请内存的时候,堆首先试图在自己的空间内找到可分配的空闲内存,如果找不到,那么就向系统申请,然后把申请到的资源整合到自己的空间中,然后再返回给用户。操作系统管理内存最小单位是页,堆向系统申请资源的时候也是页为单位分配。用户从堆中申请的资源一定要精确的释放掉。好的编程习惯是new和delete成对出现,一旦写下了new,在下一行就写下delete。
4. stack area: 栈,就两个操作,入栈和出栈。当call一个函数的时候就会在栈中压入一定的空间。等到函数执行完了就退栈,把这段空间归还回去。在内存中是由高地址向低地址生。机器会有专门的寄存器存储栈的地址也会有专门的机器指令来操作栈,所以栈的操作是比较快的。如果栈不断的被压入元素,当内存吃光了之后,系统会报错。在windows下栈的大小是2M(或者1M,有争议),这个大小是编译器预先设定好的。当函数开始后入栈顺序:栈顶指针, 参数, 局部变量。退栈的顺序与这个顺序相反。通过C++翻译的汇编语言我们能看到,使用栈中的局部变量比使用堆中的快。
5. coment area: 文字常量区。存储字符串。
2. 内存分配
1. code area。 在程序编译好的时候,这个内存就已经分配好了,全局变量和static变量都已经地址确定。
2. stack area。 在程序运行的时候,有对应的机器指令和寄存器来处理,所以,速度是很快的。
3. heap area。 用户自己申请,自己维护。用户需要使用 malloc函数或者new等函数或者关键字来申请/释放内存。如果使用不当会导致内存泄露等问题。
3. 题外话:new/delete 与 malloc/free 比较
new 和 malloc 函数 都是从堆空间上申请内存。
new 会调用类的构造函数; malloc是接受一个 unsigned long 型的值,从而给出这么大的一个空间。
delete 会调用析构函数; free 释放空间。
P.S. 堆栈总是连着说,是因为堆是从低地址向高地址生长, 栈是相反的从高地址向地址生长。于是总是,先堆后栈。对底层机器代码的研究可以揭示,栈是机器系统提供的数据结构,而堆则是C/C++函数库提供的。堆的效率要比栈的效率低。
参考文献:
C/C++ 内存分配方式,堆区,栈区,new/delete/malloc/free http://blog.sciencenet.cn/blog-268057-366795.html
c/c++里的 堆区 栈区 静态区 文字常量区 程序代码区 http://www.cnblogs.com/chenleiustc/archive/2011/04/08/2009994.html