内存布局
在C++中内存分为5个区,分别是堆、栈、自由存储区、全局/静态存储区和常量存储区。
堆:堆是操作系统中的术语,是操作系统所维护的一块特殊内存,用于程序的内存动态分配,C语言使用malloc从堆上分配内存,使用free释放已分配的对应内存。
栈:保存局部变量和函数参数等。栈上的内容只在函数的范围内存在,当函数运行结束,这些内容也会自动被销毁。栈内存分配运算内置于处理器的指令集中,效率很高,但是分配的内存容量有限。
自由存储区:自由存储区是C++基于new操作符的一个抽象概念,凡是通过new操作符进行内存申请,该内存即为自由存储区。
全局/静态存储区全局/静态存储区:这块内存是在程序编译的时候就已经分配好的,在程序整个运行期间都存在。例如全局变量,静态变量。包括DATA段(全局初始化区)与BBS段(全局未初始化段)
常量存储区常量存储区:这是一块比较特殊的存储区,他们里面存放的是常量(const),不允许修改。
简单示例:
#include <iostream>
using namespace std;
int a = 0; //全局初始化区
char *p1; //全局未初始化区
int main()
{
int b; //栈
char s[] = "abc"; //栈
char *p2; //栈
char *p3 = "123456"; //123456在常量区,p3在栈上。
static int c = 0; //全局(静态)初始化区
p1 = (char *)malloc(10);
p2 = (char *)malloc(20);//分配得来得10和20字节的区域就在堆区。
int *p4 = new int(10); //自由存储区
strcpy(p1, "123456"); //123456放在常量区,编译器可能会将它与p3所指向的"123456"优化成一个地方。
}
堆和自由存储区的区别
堆(heap)C语言和操作系统的术语,堆是操作系统所维护的一块特殊内存,它提供了动态分配的功能,当运行程序调用malloc()时就会从中分配,调用free()归还内存。
自由存储区(free store)是C++中通过new和delete动态分配和释放对象的抽象概念,通过new来申请的内存区域可称为自由存储区,通过delete归还内存。
基本上,所有的C++编译器默认使用堆来实现自由存储,运算符new和delete内部默认是使用malloc和free的方式来被实现,默认的全局运算符new和delete也许会使用malloc和free的方式申请和释放存储空间,也就是说自由存储区就位于堆上。
new和delete是运算符。运算符可以重载,当new被程序员重载,且内部实现并非只有malloc()时,此时的内存空间就和堆不同了,这是一块组合的内存空间,C++中称为“自由存储区”,这是一个抽象的概念。
new和malloc的区别
new、delete原则
1、不要使用delete来释放不是new分配的内存
2、不要使用delete释放同一个内存块2次
3、如果使用new[]为数组分配内存,则应使用delete[]来释放
4、如果使用new[]为一个实体分配内存,则应使用delete来释放
5、对空指针使用delete是安全的
6、用 malloc 或 new 申请内存之后,应该立即检查指针值是否为 NULL。防止使用指针值为 NULL 的内存。
7、不要忘记为数组和动态内存赋初值。防止将未被初始化的内存作为右值使用。
8、避免数组或指针的下标越界,特别要当心发生“多 1”或者“少 1”操作。
9、动态内存的申请与释放必须配对,防止内存泄漏。
10、用 free 或 delete 释放了内存之后,立即将指针设置为 NULL,防止产生“野指针”
堆和栈的区别
定义:
栈区(stack):由编译器自动分配释放,存放函数的参数值,局部变量等值。其操作方式类似于数据结构中的栈。
堆区(heap):一般由程序员分配释放,若程序员不释放,则可能会引起内存泄漏。注堆和数据结构中的堆栈不一样,其类似于链表。
堆和栈中的存储内容:
(1)栈:在函数调用时,第一个进栈的主函数中后的下一条语句的地址,然后是函数的各个参数,参数是从右往左入栈的,然后是函数中的局部变量。注:静态变量是不入栈的。当本次函数调用结束后,局部变量先出栈,然后是参数,最后栈顶指针指向最开始存的地址,也就是主函数中的下一条指令,程序由该点继续执行。
(2)堆:一般是在堆的头部用一个字节存放堆的大小。
区别:
1)空间大小:栈的内存空间是连续的,空间大小通常是系统预先规定好的,即栈顶地址和最大空间是确定的;而堆得内存空间是不连续的,由一个记录空间空间的链表负责管理,因此内存空间几乎没有限制,在32位系统下,内存空间大小可达到4G
2)管理方式:栈由编译器自动分配和释放,而堆需要程序员来手动分配和释放,若忘记delete,容易产生内存泄漏。
3)生长方向不同:对于栈,他是向着内存地址减小的方向生长的,这也是为什么栈的内存空间是有限的;而堆是向着内存地址增大的方向生长的
4)碎片问题:由于栈的内存空间是连续的,先进后出的方式保证不会产生零碎的空间;而堆分配方式是每次在空闲链表中遍历到第一个大于申请空间的节点,每次分配的空间大小一般不会正好等于申请的内存大小,频繁的new操作势必会产生大量的空间碎片
5)分配效率:栈属于机器系统提供的数据结构,计算机会在底层对栈提供支持,出栈进栈由专门的指令执行,因此效率较高。而堆是c/c++函数库提供的,当申请空间时需要按照一定的算法搜索足够大小的内存空间,当没有足够的空间时,还需要额外的处理,因此效率较低。
栈 | 堆 | |
---|---|---|
管理方式 | 编译器自动分配管理 | 程序员手动分配释放,容易引起内存泄漏 |
空间大小 | 大小固定,超出overflow | 计算机系统中有效的虚拟内存 |
管理方式 | 速度快,效率高 | 速度慢,效率低,容易产生碎片 |
管理方式 | 静态分配和动态分配 | 动态分配 |