C/C++中的内存区域
目录
1.代码段(常量区)
2.数据段(静态区)
3.栈区
4.堆区
5.小结(堆与栈的区别)
C/C++程序内存区域划分图:
1.代码段(常量区)
存放常量和程序代码(二进制代码)的区域
2.数据段(静态区)
存放全局变量和静态数据, 程序结束时由系统释放
(用static修饰的变量会存入静态区, 会改变其生命周期, 程序结束时由系统释放)
3.栈区
1).栈区处于相对较高的地址, 如图,栈地址是向下(向低地址)增长的, 是一块连续的内存的区域.
2).在执行函数时, 函数中的局部变量(不包括局部静态变量)在栈中存放
3).函数执行完毕这些局部变量都会被释放, 栈内存分配运算内置于处理器的指令集中,效率很高,但是分配的内存容量有
限。 栈区主要存放运行函数时分配的局部变量、函数参数、返回数据、返回地址
4).只要栈区的剩余空间大于所申请空间,系统将为程序提供内存,否则将报异常提示栈溢出。栈顶的地址和栈的最大容量是系统预先规定好的,在 Windows下,栈的大小是2M(也有的说是1M,总之是一个编译时就确定的常数),如果申请的空间超过栈的剩余空间时,将提示overflow
4.堆区
1).动态分配的内存在堆区
2).一般由程序员分配和释放, 若程序员不释放(不及时释放会造成内存泄漏), 则程序运行结束时会由操作系统(OS)回收, 分配方式有些类似于链表
3).首先应该知道操作系统有一个记录空闲内存地址的链表,当系统收到程序的动态开辟内存的申请时,会遍历该链表,寻找第一个空间大于所申请空间的堆结点,然后将该结点从空闲结点链表中删除,并将该结点的空间分配给程序,另外,对于大多数系统,会在这块内存空间中的首地址处记录本次分配的大小,这样,代码中的 C中free()函数(C++中delete语句)才能正确的释放申请的内存空间。此外,由于找到的堆结点的大小不一定正好等于申请的大小,系统会自动的将多余的那部分重新放入空闲链表中。
4).C中由动态开辟内存的函数( malloc(), calloc(), realloc() )分配(C++中由new分配), 速度较慢, 易产生内存碎片, 但使用比较方便
5).堆是由低地址向高地址扩展的,是不连续的内存区域。这是由于系统是用链表来存储的空闲内存地址的,自然是不连续的,而链表的遍历方向是由低地址向高地址。堆的大小受限于计算机系统中有效的虚拟内存。堆获得的空间比较灵活,也比较大。
5.小结(堆与栈的区别)
1).申请和回收
栈 : 系统完成
堆 : 程序员完成(如果不及时手动回收会造成内存泄漏,所以一般要由程序员完成)
2).申请效率
栈 : 较快(栈内存分配运算内置于处理器的指令集中,效率高)
堆 : 较慢(C中由动态开辟内存的函数( malloc(), calloc(), realloc() )分配(C++中由new分配), 较慢)
3).申请大小的限制
栈 : 较小 (在Windows下,栈的大小是2M(也有的说是1M,总之是一个编译时就确定的常数) )
堆 : 大 (堆的大小受限于计算机系统中有效的虚拟内存)
由于栈的大小有限,所以用子函数还是有物理意义的,而不仅仅是逻辑意义。物理意义在于, 数据需要用时入栈, 不需要用时出栈, 提高了内存空间的利用率, 避免出现不再使用的数据占据内存的情况. 也就是说如果不用子函数,主函数中就可能会定义非常多的局部变量, 而有些变量函数运行到某处后就可能不再使用, 这些变量却还一直在栈中, 占用内存 .
4).堆和栈中的存储内容
栈 : 在函数调用时,第一个进栈的是主函数中函数调用后的下一条指令(函数调用语句的下一条可执行语句)的地址,然后 后是函数的各个参数,在大多数的C编译器中,参数是由右往左入栈的,然后函数中的局部变量依次入栈。函数调用结束时, 先入栈的后出栈, 后入栈的先出栈.
堆 : 堆中的具体内容由程序员决定