C++_内存管理

C++内存管理

C++ 内存分区:栈、堆、全局/静态存储区、常量存储区、代码区。

:存放函数的局部变量、函数参数、返回地址等,由编译器自动分配和释放。
:动态申请的内存空间,就是由 malloc 分配的内存块,由程序员控制它的分配和释放,如果程序执行结束还没有释放,操作系统会自动回收。
全局区/静态存储区(.bss 段和 .data 段):存放全局变量和静态变量,程序运行结束操作系统自动释放,在 C 语言中,未初始化的放在 .bss 段中,初始化的放在 .data 段中,C++ 中不再区分了。
常量存储区(.data 段):存放的是常量,不允许修改,程序运行结束自动释放。
代码区(.text 段):存放代码,不允许修改,但可以执行。编译后的二进制文件存放在这里。

栈和堆的区别

栈是由操作系统自动创建,堆是可以由程序员来进行控制

通常在程序中声明一个变量 如

1
2
3
4
5
int fun1()
{
int a = 0;
int *b = new int[];
}

这个变量a就是被创建在栈上,而这个变量b就是被创建在堆上。

栈是由大小限制的,一般来说编译器的默认大小是1M,如果申请的变量过大,有可能造成栈溢出,即StackOverFlow,不过这个大小可以通过配置修改扩大。堆一般就是内存的大小,一般创建在堆上的变量在使用完成后需要程序员自行进行回收,否则会出现不可预知的错误。

内存对齐

C++内存按照编译器的设置,按照内存块来存储的,这个内存块大小的取值,就是内存对齐。

1
2
3
4
5
6
struct foo
{
char a; //1 byte
int b ; // 4 byte
short c; // 2 byte
}

sizeof(foo)的大小是12,编译器会将char和short的大小和int的大小进行对齐。

1、第一个数据成员放在offset为0的地方,以后每个数据成员的对齐按照#pragma pack指定的数值和这个数据成员自身长度中,比较小的那个进行。

2、在数据成员完成各自对齐之后,类(结构或联合)本身也要进行对齐,对齐将按照#pragma pack指定的数值和结构(或联合)最大数据成员长度中,比较小的那个进行。

很明显#pragma pack(n)作为一个预编译指令用来设置多少个字节对齐的。值得注意的是,n的缺省数值是按照编译器自身设置,一般为8,合法的数值分别是1、2、4、8、16。
即编译器只会按照1、2、4、8、16的方式分割内存。若n为其他值,是无效的。

所以如果

1
2
3
4
5
6
7
#pragma pack(1)//设定为 1 字节对齐
struct foo
{
char a; //1 byte
int b ; // 4 byte
short c; // 2 byte
}

这时sizeof(foo)的大小就是7字节