虚拟内存布局
Linux 内核给每个进程都提供了一个独立的虚拟地址空间,并且这个地址空间是连续的。这样,进程就可以很方便地访问内存,更确切地说是访问虚拟内存。虚拟地址空间的内部又被分为内核空间和用户空间两部分,
不同字长(也就是单个 CPU 指令可以处理数据的最大长度)的处理器,地址空间的范围也不同。32 位系统的内核空间占用 1G,位于最高处,剩下的 3G 是用户空间。而 64 位系统的内核空间和用户空间都是 128T,分别占据整个内存空间的最高和最低处,剩下的中间部分是未定义的。
image用户态空间分布
用户空间主要用来存储如下数据:
- 程序代码
- 全局变量
- 常量字符串
- 函数栈,存放方法局部变量
- 堆,申请一小块内存,存放在堆中
- glibc关联函数代码
Text Segment
是存放二进制可执行代码的位置
Data Segment
存放静态常量,从高地址开始向下增长
BSS Segment
存放未初始化的静态变量
堆
malloc函数申请一小块内存,存放在堆中,从低地址开始向上增长
mmap映射区
-
mmap用来存放malloc函数申请一大块内存区域,mmap不仅仅可以用来映射物理内存同时也可以用来映射文件,所谓映射文件就时将文件数据拷贝到物理内存中某个区域,这块区域通过页表映射到用户mmap映射区中。这样用户可以像访问内存一样访问文件。
-
当mmap区域映射到文件时我们称为文件映射,非文件时称为匿名映射。
-
当内存空间不足时可以将内存数据写入磁盘中的某个文件,这个过程称为换出,当进程访问这些内存时,再从磁盘读取这些数据到内存中这个过程称为换入。而这个写入的文件被称为swap文件
栈
这块地址用来存放方法局部变量,从高地址开始向下增长
内核态空间分布
内核空间主要用来存储如下数据
- 内核的代码要在内存里面;
- 内核中也有全局变量;
- 每个进程都要有一个 task_struct;
- 每个进程还有一个内核栈;
- 在内核里面也有动态分配的内存;
- 虚拟地址到物理地址的映射表
内核态的虚拟空间和某一个进程没有关系,所有进程通过系统调用进入到内核之后,看到的虚拟地址空间都是一样的。在内核态,32 位和 64 位的布局差别比较大,主要是因为 32 位内核态空间太小了。
32位操作系统内核空间
image直接映射区
直接映射区,就是这一块空间是连续的,和物理内存是非常简单的映射关系,直接宏函数就得到物理内存的位置,大小为896M,其中前 1M 已经在系统启动的时候被占用,1M之后到896M主要用来存储内核代码 ,内核的全局变量,内核栈。
//运算规则 虚拟内存地址减去 3G,就得到物理内存的位置
__pa(vaddr) 返回与虚拟地址 vaddr 相关的物理地址;
__va(paddr) 则计算出对应于物理地址 paddr 的虚拟地址。
内核动态映射空间 vmalloc区
用来申请内核动态分配的内存(使用vmalloc函数)
持久内核映射
用来存储内核进程数据结构 task_struct
固定映射区域
主要用于满足特殊需求
最后区域
用户态的进程要映射一个文件到内存中,先要映射用户态进程空间的一段虚拟地址到物理内存,然后将文件内容写入这个物理内存供用户态进程访问。但对于操作系统而言能够操作硬件资源只能时操作系统内核来完成。
image
网友评论