一张图详解C++内存分布(通俗易懂)
C++的类类似于C中的结构体声明,对象则类似于结构体的实例化。每个程序运行起来后,都拥有自己独立的虚拟地址空间。32位地址硬件平台的虚拟空间地址就是0 ~ 2^32 -1,即0x00000000 ~ 0xFFFFFFFF(42949677295byte),总共为4GB的大小。**
- 内存的3种分配方式
-[] 从静态存储区分配:内存在程序编译的时候就分配好了,这块内存在程序的整个运行期间都存在。例如:全局变量,static变量
-[] 在栈上创建:执行函数时,函数内部的局部变量存储单元可以在栈上创建。栈内存分配运算内置于处理器的指令集,效率高,但是分配的内存容量有限。
-[] 在堆上分配:称为动态内存分配,程序在运行的时候使用malloc或new申请任意多少的内存,程序员自己负责使用free或delete释放内存。如果在堆上分配了空间,若不回收,则运行的程序会出现内存泄漏。频繁的分配和释放不同大小的堆空间会产生内存碎片(因为堆是操作系统采用空闲链表的形式分配的,链表存放的地址是不连续的)。
栈和堆的比较
栈(static) | 堆(heap) | |
---|---|---|
申请方式 | 系统自动分配 | 程序员申请 |
申请效率 | 栈是系统自动分配的,速度较快 | 堆是由new分配的,速度较慢,且容易产生内存碎片,但使用方便 |
申请大小的限制 | 在window系统中,栈是向低地址扩展的数据结构,是一块连续的内存。栈顶的地址和栈的最大容量是系统预先规定好的。window下,栈的大小是2M(能从栈获取的空间较小)。如果申请的空间超过栈的剩余空间,将提示overflow | 堆是向高地址扩展的数据结构,由于操作系统用链表来存储空闲内存地址,故堆是不连续的内存区域,而且链表的遍历方向是低地址向高地址。由于堆获取的空间受限于操作系统中有效的虚拟内存,故比较灵活,且能获取的堆空间较大 |
系统响应方式 | 只要系统剩余空间大于申请空间就能申请,否则报错:栈溢出 | 操作系统有一个记录空闲地址的链表,当系统收到内存申请的请求时,会遍历该链表,寻找第一个空间大于申请空间的堆结点,然后将该结点从空闲结点链表中删除,并将该结点的空间分配给程序。由于找到的堆结点的有可能会大于申请的内存大小,系统会自动将多余的那部分重新放入到空闲链表中 |