C++内存管理
C++ 内存分区:栈、堆、全局/静态存储区、常量存储区、代码区。
栈:存放函数的局部变量、函数参数、返回地址等,由编译器自动分配和释放。
堆:动态申请的内存空间,就是由 malloc 分配的内存块,由程序员控制它的分配和释放,如果程序执行结束还没有释放,操作系统会自动回收。
全局区/静态存储区(.bss 段和 .data 段):存放全局变量和静态变量,程序运行结束操作系统自动释放,在 C 语言中,未初始化的放在 .bss 段中,初始化的放在 .data 段中,C++ 中不再区分了。
常量存储区(.data 段):存放的是常量,不允许修改,程序运行结束自动释放。
代码区(.text 段):存放代码,不允许修改,但可以执行。编译后的二进制文件存放在这里。
栈和堆的区别
栈是由操作系统自动创建,堆是可以由程序员来进行控制
通常在程序中声明一个变量 如
1 | int fun1() |
这个变量a就是被创建在栈上,而这个变量b就是被创建在堆上。
栈是由大小限制的,一般来说编译器的默认大小是1M,如果申请的变量过大,有可能造成栈溢出,即StackOverFlow,不过这个大小可以通过配置修改扩大。堆一般就是内存的大小,一般创建在堆上的变量在使用完成后需要程序员自行进行回收,否则会出现不可预知的错误。
内存对齐
C++内存按照编译器的设置,按照内存块来存储的,这个内存块大小的取值,就是内存对齐。
如
1 | struct foo |
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 | #pragma pack(1)//设定为 1 字节对齐 |
这时sizeof(foo)的大小就是7字节