堆栈部分的介绍在上一篇也有详细的介绍,可以结合上一篇博文进行结合阅读:C / C++系列 (3):heap vs. stack & new vs. malloc
变量内存分配的方式
内存分配有三种方式:
- 从静态存储区域 分配。内存在程序编译的时候就已经分配好,这块内存在程序的整个运行期间都存在。例如全局变量 ,static变量 。
- 在栈 上创建。在执行函数时,函数内局部变量 的存储单元都可以在栈上创建,还包括static修饰的局部变量也在栈上,函数执行结束时这些存储单元自动被释放。栈内存分配运算内置于处理器的指令集中,效率很高,但是分配的内存容量有限。
- 从堆 上分配,亦称动态内存分配。程序在运行的时候用malloc 或new 申请任意多少的内存,程序员自己负责在何时用free或delete释放内存。动态内存的生存期由程序员决定,使用非常灵活,但如果在堆上分配了空间,就有责任回收它,否则运行的程序会出现内存泄漏,频繁地分配和释放不同大小的堆空间将会产生堆内碎块。
malloc的底层实现
malloc函数的实质是它有一个将可用的内存块连接为一个长长的列表的所谓空闲链表。 调用malloc()函数时,它沿着连接表寻找一个大到足以满足用户请求所需要的内存块。 然后,将该内存块一分为二(一块的大小与用户申请的大小相等,另一块的大小就是剩下来的字节)。 接下来,将分配给用户的那块内存存储区域传给用户,并将剩下的那块(如果有的话)返回到连接表上。 调用free函数时,它将用户释放的内存块连接到空闲链表上。 到最后,空闲链会被切成很多的小内存片段,如果这时用户申请一个大的内存片段, 那么空闲链表上可能没有可以满足用户要求的片段了。于是,malloc()函数请求延时,并开始在空闲链表上检查各内存片段,对它们进行内存整理,将相邻的小空闲块合并成较大的内存块。
基于以上理解,malloc()的申请大小由于内存的剩余大小而改变。特别的是,malloc接触的内存空间是虚拟内存 ,所以对于32位window系统,内核/用户为2:2分配,故最大申请空间大约为1.9G(虚拟内存4G);对于linux系统,内核/用户为1:3分配,故最大申请空间大约2.9G(虚拟内存4G)。实际上,具体的数值会受到操作系统版本、程序本身的大小、用到的动态/共享库数量、大小、程序栈数量、大小等的影响,甚至每次运行的结果都可能存在差异。
满足以上条件,只要不进行memset就不会发生错误。
Linux虚拟地址空间布局
此部分参考来源: