@todo: OneNote 笔记 copy 过来(内核如何使用 task_struct -> mm_struct 管理进程内存布局)
进程的内存布局(32位)
在32位 Linux 系统中,每个进程都有4GB 的虚拟地址空间,其中0-3GB 是用户空间,3-4GB 是内核空间。每个进程都以为自己独占整个4GB 的地址空间,但实际上1GB 的内核空间是所有进程共享的,独占的3GB 用户空间也只是虚拟的。
|
内存布局从高地址到低地址:
Kernel
: 内核空间在页表中拥有较高的特权级(ring 2或以下), 因此只要用户态的程序试图访问这些页, 就会导致一个页错误(page fault), 用户程序不可访问内核页Stack
: 自高地址向低地址增长, 每个进程都有一个自己的栈, 当不断压栈直到超过了最大的栈空间, 将会引起Stack Overflow, 进程中的每一个线程都有属于自己的栈Memory Mapping Segment
: mmap()实现”文件-内存映射”, 它被用于加载动态库, 大多数实际的malloc实现会考虑通过mmap分配较大块的内存区域, 这个区域自高地址向低地址增长Heap
: malloc()分配的内存空间, 如果堆中有足够的空间来满足内存请求, 它就可以被语言运行时库处理而不需要内核参与. 否则堆会被扩大, 通过brk()
系统调用来分配请求所需的内存块, 堆自低地址向高地址增长BSS Segment
: 未赋初始值的static变量, 包括全局的static变量和函数内定义的static变量(全局变量默认就是static)Data Segment
: 有初始值的static变量, 程序bin映像的一部分- 还包括一个叫
rodata
的区域, 存储”字面量字符串”(包括全局/局部定义的字面量字符串), 以及”const 常量”
- 还包括一个叫
Text Segment
: 这里存放的是二进制代码
C 代码中的 const、static 在 Data Segment 的存储细节,解释参考 GNU的obj分析工具的使用 - nm/objdump | 扔掉笔记 ᐛ
其中高地址的 1GB Kernel Space 结构如下(左边):
进程的内存布局(64位)
64位架构下内存布局与32位类似, 可寻址64TB(Intel架构下是46个地址线, 2^46)
How to 查看某个进程的内存分布
命令行:cat /proc/xxx/maps