一、内存分布图
高地址
┌─────────────────┐
│ 栈(stack) │ ← 局部变量、函数调用等
├─────────────────┤
│ ↓ │
│ 空洞/未使用 │
│ ↑ │
├─────────────────┤
│ 内存映射区域 │ ← mmap的文件、共享内存等
├─────────────────┤
│ 堆(heap) │ ← malloc/new分配的内存
├─────────────────┤
│ BSS段(.bss) │ ← 未初始化全局/静态变量
├─────────────────┤
│ 数据段(.data) │ ← 已初始化全局/静态变量
├─────────────────┤
│ 代码段(.text) │ ← 程序代码
└─────────────────┘
低地址
二、详细说明
- 代码段(Text segment):
- 也称为只读段,存放程序的执行代码(机器指令)。
- 通常是只读的,防止程序意外修改指令。
- 也可能包含一些只读的常量数据,例如字符串常量。(为什么说可能?)
- 数据段(Data segment):
- 初始化数据段(Data segment):
存放全局变量和静态变量(包括全局静态变量和局部静态变量)中已经初始化的部分。 - 未初始化数据段(BSS segment):
存放全局变量和静态变量中未初始化的部分。在程序开始执行之前,系统会将BSS段的数据初始化为0或空指针。两者有何区别?
- 初始化数据段(Data segment):
- 堆(Heap):
- 用于动态内存分配,例如使用malloc、new等分配的内存。
- 堆的生长方向是从低地址向高地址增长。
- 需要手动管理内存(在C++中,使用new分配的内存必须使用delete释放,否则会造成内存泄漏)。
- 栈(Stack):
- 用于存放局部变量、函数参数、返回地址等。
- 栈的生长方向是从高地址向低地址增长。
- 栈由编译器自动管理,当函数调用结束时,其栈帧被自动销毁。
- 内存映射区域(Memory mapping segment):
- 用于映射动态链接库、文件映射等。
三、验证
#include <iostream>
#include <fcntl.h>
#include <memory>
#include <sys/mman.h>
#include <unistd.h>
#include <iomanip>
using namespace std;
// 全局变量 - 数据段
int global_init = 10; // 已初始化数据段
int global_uninit; // BSS段
int main() {
std::cout << "main函数 地址: " << (void*)main << std::endl;
//栈-局部变量
int local = 20;
// 静态局部变量 - 数据段
static int static_local = 30;
// 静态局部变量 - 数据段
static int static_local1;
// 堆: 动态分配
int* heap_var = new int(40);
// 代码段: 常量字符串
const char* str = "Hello";
//内存映射:
int fd = open("/home/235039/test/MmapBuf.test", O_RDWR | O_CREAT, 00777);
if(fd == -1)
{
return -1;
}
auto closeFD = [](int* fd) {
if (fd && *fd >= 0) {
close(*fd);
}
delete fd;
};
std::unique_ptr<int, decltype(closeFD)> ptr(new int(fd), closeFD);
char *pMmapBuf = (char *) mmap(NULL, 100, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
if(pMmapBuf == MAP_FAILED)
{
return -1;
}
cout << "栈- 局部变量地址: " << &local << endl;
cout << "内存映射- 映射地址:" << (void*)pMmapBuf<<endl;
cout << "堆- 变量地址: " << heap_var << endl;
cout << "数据段-全局未初始地址: " << &global_uninit << endl;
cout << "数据段-静态局部未初地址: " << &static_local1 << endl;
cout << "数据段-全局初始化地址: " << &global_init << endl;
cout << "数据段-静态局部初始地址: " << &static_local << endl;
cout << "代码段-常量字符串地址: " << (void*)str << endl;
delete heap_var;
munmap(pMmapBuf, 100);
return 0;
}
验证结论:
