可执行文件(包括 exe, dll)使用的格式叫 PE 格式,这种格式把内容按区段进行存储,用一些 PE 工具就可以查看这些区段,每个区段除了大小,内容外还有一个属性,表示是否可读,可写,可执行,可共享等等.常用的区段包括:
.text 代码段
.data 数据段
.rdata 只读数据段
.bss 未初始化数据段
.rc 资源段 等等。
Window 启动进程的时候基本上会按照原样把这些区段映射到内存中,我们姑且把这部分内存叫做静态内存吧。
然后系统会启动主线程,主线程可能再去启动其他线程,每一个线程启动的时候系统都会为这个线程分配一块内存,用于在这个线程中执行 push, pop 这些指令。这块内存就是栈内存。另外程序在运行的过程中还可以随时向系统申请内存,虽然方式有多种,但是最常见的是通过 HeapAlloc 来分配的,这种内存称为堆内存。这三种是最主要的,其它的内存比如还有线程局部存储区 TLS,共享内存,托管内存,显存等等,这里就不管了。
C++ 使用的内存最终都会对应到上边的去,首先全局变量和静态变量会被编译到 PE 文件中的 .data 数据段,一般编译器会自动初始化为 0, 将其写入bss段,前提是你没有初始化,比如int max ;定义了全局变量,但是没有初始化,是不会写入data数据段的,再比如int max={0},也是同一个道理。
字符串常量会被编译到只读数据段中,这也是 char* x="hello"; x[0] = 'e'; 会出错的原因,因为 "hello" 这块内存是只读的。但是一般来说定义 const 并不会使你的变量就分配到只读数据段中去的。
函数内定义的非静态变量,函数参数都是程序执行到函数这里来了后临时在栈中留一块区域出来,完了就收回的。
最后 new 的内存很明显属于堆内存。
一般而言,计算机程序由代码和数据组成,这两个部分是影响程序所需要内存的重要因素。代码是程序运行的指令,数据则是代码要处理的对象,下面重点讨论一下:
一个程序占有的内存分为5类:
1. 全局/静态数据区---->对应 .data数据段
2.常量数据区--> .rdata只读数据段
3.代码区---> .text代码段 (存储代码)
4.栈
5.堆
内存存储情况:
1. 全局/静态数据区---> 全局/静态数据
2.常量数据区(.rdata)-->常量字符串
3.栈---->自动变量或者局部变量,以及传递的函数参数
4.堆--->用户控制 new/malloc出来的内存,注意内存泄露问题
下面通过具体代码查看数据的存储问题:
- #include <stdio.h>
- #include <stdlib.h>
- int nGlobal = 200;
- int main()
- {
- char *pLocalString1 = "LocalString1";
- const char *pLocalString2 = "LocalString2";
- static int nLocalStatic = 100;
- int nLocal = 1;
- const int nLocalConst = 20;
- int * pNew = (int *)malloc(sizeof(int)*5);;
- char *pMalloc = (char *)malloc(1);
- //全局/静态数据区
- printf("全局/静态数据区:/n");
- printf("global variable: 0x%x/n", &nGlobal);
- printf("static variable: 0x%x/n/n", &nLocalStatic);
- //常量区
- printf("常量区:/n");
- printf("pLocalString1 variable: 0x%x/n", pLocalString1);
- printf("pLocalString2 variable: 0x%x/n", pLocalString2);
- printf("nLocalConst variable: 0x%x/n/n", nLocalConst);
- //堆
- printf("堆:/n");
- printf("new variable: 0x%x/n", pNew);
- printf("malloc variable: 0x%x/n/n", pMalloc);
- //栈
- printf("栈:/n");
- printf("pointer pnew variable: 0x%x/n", &pNew);
- printf("pointer malloc variable: 0x%x/n", &pMalloc);
- printf("nLocal variable: 0x%x/n", &nLocal);
- printf("pointer pLocalString1 variable: 0x%x/n", &pLocalString1);
- printf("pointer pLocalString2 variable: 0x%x/n", &pLocalString2);
- printf("nLocalConst variable: 0x%x/n/n", &nLocalConst);
- return 0;
- }
下面是运行结果:
我们可以看到栈和堆的内存都存在内存对齐的。 堆的内存是按照34个字节对齐(我的机器是这样的)的。
下面是各个数据所在区间的对应关系: