目录
1.内存模型逻辑划分
在C++中,虚拟内存通常会被划分成5个区域,分别是堆、栈、全局/静态存储区、常量存储区、代码区。下面简单介绍下。
1.堆(heap)
在程序运行期间使用,用来存储动态分配的变量。C语言用malloc开辟堆空间、C++语言用new开辟堆空间。堆释放原则是,谁开辟,谁释放。如果不释放,就会造成内存泄漏,常见的OOM报错就是这种。如果没有释放,在程序结束后,操作系统会回收堆空间内存。
2.栈(stack)
栈是由编译器自动分配和释放,不需要程序员自行维护。像局部变量、函数传参都是存储在栈区。函数结束后,局部变量自动释放。
栈空间远小于堆,一般只有10MB左右。
3.全局静态存储区(.bss段和.data段)
有些叫全局区,有些叫静态区,有些甚至不在区分这么细了。其实叫什么无所谓,这两个都是在同一块内存中。存储的都是全局变量和静态变量。只是一个存储已经初始化的变量,一个存储未初始化的变量。
.bss段:存放未初始化的全局变量和静态变量。如 static int aa;
.data段:存放初始化了的全局变量和静态变量。如 static int aa = 100;
对于未初始化的全局变量和静态变量,程序启动后,编译器会默认赋予初始值。是int类型,就赋予0,字符串类型就赋予"",指针类型,就赋予nullptr。
4.常量存储区(.rodata段)
用来存储字符串常量、const修饰的常量。不能被修改。如
const char* str = "hello world"; // "hello world" 在常量区
const int MAX_NUM = 1000; // 全局const常量
5.代码区(.text段)
代码段也被称为文本区或只读区,存放程序的二进制代码,代码段是只读的,可以被多个进程共享。
2.内存模型对应磁盘文件说明
以Windows举例,程序编译好后,我们实际得到的是一个exe文件。里面存放的就是上面各个段的二进制内容。不过需要注意的是:.text/.rodata/.data/.bss这些内容会被打包到exe中,但堆和栈不会。他们不属于 exe 文件内容,是程序跑起来后才创建的内存。
3.程序加载过程
这一步就是第2步的反向过程。
操作系统加载exe时,会把文件内部的段映射到进程虚拟内存五大分区中。其中:
exe中的.text内容映射到内存代码区中,只读。
exe中的.rodata内容映射到内存常量存储区中,只读。
exe中的.data和.bss内容映射到内存全局静态存储区中,其中.bss在运行时会被清空,这也是为啥没有赋值的全局变量、静态变量也会有默认值而不是垃圾值的原因。可读写。
堆、栈,exe文件中不存在,是程序启动后操作系统自行创建的。