总结自网络资料,做了部分验证。
——————————————————————————————————————————
Linux为进程提供4GB的虚拟内存(如果不了解虚拟内存,就当成物理内存)。如果把内存想象成从地址低到高的顺序表,竖着放,地址高在上,低在下。(更严谨一点,小端模式下)
则从上到下,从高到低,内存中储存的内容依次为:
内核
栈 ↓
MMAP ↓
堆 ↑
.bss
.data
.rodata
.text
保留区域
1、内核
大小1GB。
用户代码不可访问,内核态可访问。
2、栈
上面是内核,不可访问,正好作为栈底。
大小8MB,储存函数相关内容:函数返回点、函数参数、临时变量。
函数结束时,依次将上述内容出栈,最后返回函数调用点,执行后续代码。
由编译器分配,速度快。
可以通过alloca手动申请。
增加的内容向下扩展。
3、MMAP
此区域用于一一映射文件中的内容,像操作文件一样操作内存,操作系统会在一定延时后将修改写入磁盘,可以通过调用函数设置无延时。 <sys/mman.h> mmap()
增加的内容向下扩展。
4、堆
用于动态申请的内存。
由于申请和释放并不同步,所以堆上通常有大量内存碎片,每个内存碎片起始处储存当前碎片的大小和下一个碎片的起始地址,形成链表一样的结构。
程序员动态申请内存时,程序查找链表上合适的内存段分配,然后将新形成的碎片的信息加入链表,释放时进行类似的操作。
堆的申请由C/C++函数库提供,涉及复杂的算法,申请速度相对较慢。
增加的内容向上扩展。
5、.bss
在程序的物理文件中,未初始化的全局变量和静态变量不需要空间储存,但仍需记录总大小。程序运行时在BSS段内存分配记录大小的全零区域。运行时为它们赋值不会把它们存到其他地方。
6、.data
已初始化的全局变量、静态变量储存在这片区域。
7、.rodata
只读数据区。
常量储存在这片区域
注:部分资料可能将上面的部分区域归到一起
7、.text
可执行文件的代码,包括操作码和操作对象,这片区域一般只读。
8、保留区域
不可访问。
———————————————————————————————————————————
测试代码,依次打印上述各区域中的内容地址。
可以看到从堆到MMAP的区域是最大的。
#include <cstdio>
#include <sys/mman.h>
#include <unistd.h>
int d;
const int e = 0;
void fun()
{
int f;
printf("%p\n", &f);
}
int main()
{
//函数main中的临时变量,在栈中
int a;
printf("%p\n", &a);
// fun中变量后入栈,地址应小于a
fun();
// MMAP区
auto b = mmap(nullptr, getpagesize(), PROT_READ, MAP_SHARED, fileno(fopen("text", "w+")), 0);
printf("%p\n", b);
// 由new动态申请的
auto c = new int;
printf("%p\n", c);
// 未初始化全局变量
printf("%p\n", &d);
// 已初始化全局变量
printf("%p\n", &e);
}
输出:
0x7ffc1f35f65c
0x7ffc1f35f63c
0x7fe75f8e9000
0x20d8250
0x601060
0x40088c
上述为运行程序内存结构。
未运行的程序包括:
.bss 未初始化全局变量或静态变量,不占物理空间,但记录总大小
.data 已初始化全局变量或静态变量、常量,占物理空间
.text 代码段