Linux 地址空间分布

转载 2013年10月28日 10:42:41

地址空间分布

  最近看了本书,突然对于地址空间有些疑惑。在深入理解linux内核中把地址分为三类:逻辑地址(汇编语言中操作数地址或指令的地址,对于80x86的cup,逻辑地址是段+段内偏移地址)、线性地址(也叫虚拟地址)和物理地址。但在Stott Maxwell的《Linux Core Kernel Commentrary》中确是这样分的:逻辑地址(也叫虚拟地址)、线性地址和物理地址。按照386 CPU总设计师 John Crowford的解释,虚拟地址是保护模式下段和段内偏移量组成的地址,而逻辑地址就是代码段内偏移量,或称进程的逻辑地址。其实对于linux来说,这三种说法都没错,由于linux下并不主张将程序分段,而是主张分页,所以即使是在80x86的体系结构下,段的基地址也是0。因此逻辑地址、线性地址、虚拟地址在linux中其实是相同的。所以对于linux下的elf可执行文件来说,代码段的起始地址0x08048000既是逻辑地址,也是线性地址也是虚拟地址。

  1 x86的物理地址空间布局:

 

  物理地址空间的顶部以下一段空间,被PCI设备的I/O内存映射占据,它们的大小和布局由PCI规范所决定。640K~1M这段地址空间被BIOSVGA适配器所占据 

  Linux系统在初始化时,会根据实际的物理内存的大小,为每个物理页面创建一个page对象,所有的page对象构成一个mem_map数组。 

进一步,针对不同的用途,Linux内核将所有的物理页面划分到3类内存管理区中,如图,分别为ZONE_DMA,ZONE_NORMAL,ZONE_HIGHMEM。 

  ZONE_DMA的范围是0~16M,该区域的物理页面专门供I/O设备的DMA使用。之所以需要单独管理DMA的物理页面,是因为DMA使用物理地址访问内存,不经过MMU,并且需要连续的缓冲区,所以为了能够提供物理上连续的缓冲区,必须从物理地址空间专门划分一段区域用于DMA 

  ZONE_NORMAL的范围是16M~896M,该区域的物理页面是内核能够直接使用的。 

  ZONE_HIGHMEM的范围是896M~结束,该区域即为高端内存,内核不能直接使用。

linux虚拟地址内核空间分布

  在kernel image下面有16M的内核空间用于DMA操作。位于内核空间高端的128M地址主要由3部分组成,分别为vmalloc area,持久化内核映射区,临时内核映射区。

  由于ZONE_NORMAL和内核线性空间存在直接映射关系,所以内核会将频繁使用的数据如kernel代码、GDT、IDT、PGD、mem_map数组等放在ZONE_NORMAL里。而将用户数据、页表(PT)等不常用数据放在ZONE_ HIGHMEM里,只在要访问这些数据时才建立映射关系(kmap())。比如,当内核要访问I/O设备存储空间时,就使用ioremap()将位于物理地址高端的mmio区内存映射到内核空间的vmalloc area中,在使用完之后便断开映射关系。 

3 linux虚拟地址用户空间分布

  用户进程的代码区一般从虚拟地址空间的0x08048000开始,这是为了便于检查空指针。代码区之上便是数据区,未初始化数据区,堆区,栈区,以及参数、全局环境变量。

4 linux虚拟地址与物理地址映射的关系

 

  Linux4G的线性地址空间分为2部分,0~3Guser space3G~4Gkernel space

  由于开启了分页机制,内核想要访问物理地址空间的话,必须先建立映射关系,然后通过虚拟地址来访问。为了能够访问所有的物理地址空间,就要将全部物理地址空间映射到1G的内核线性空间中,这显然不可能。于是,内核将0~896M的物理地址空间一对一映射到自己的线性地址空间中,这样它便可以随时访问ZONE_DMAZONE_NORMAL里的物理页面;此时内核剩下的128M线性地址空间不足以完全映射所有的ZONE_HIGHMEMLinux采取了动态映射的方法,即按需的将ZONE_HIGHMEM里的物理页面映射到kernel space的最后128M线性地址空间里,使用完之后释放映射关系,以供其它物理页面映射。虽然这样存在效率的问题,但是内核毕竟可以正常的访问所有的物理地址空间了。

5 linux中可执行程序与虚拟地址空间的映射关系

  虚拟内存区域(VMA,Virtual Memory Area)是Linux中进程虚拟地址空间中的一个段,在Windows里面叫虚拟段。当操作系统创建线程后,会在进程相应的数据结构中设置一个.text段的VMA,它在虚拟空间中的地址为0x08048000~0x08049000,它对应ELF文件中的偏移为0.text。可以查看操作系统为运行的进程维护的信息:

 

从上面的图可以看出,虚拟空间地址为0x08048000~0x08049000VMA映射为elf文件中的一个段(segment),并且是按整页进行映射的。

  由于linux下的ELF可执行文件会有很多个段(section),所以如果把每个section都映射为一个VMA,那么没有一个页大小的段(section)也会被映射为一个页的VMA,这样就浪费了物理空间,由于不足会用0补充。故elf有一个装载的段(segment),与前面的段(section)不同,前面的段(section)主要用于链接,而段(segment)主要用于装载进内存。

 

  可以看出段(segment)02包含了很多的段(section),那链接器怎样将段(section)合并到一个段(segment)中的呢?可以通过段(section)的权限来合并,如以代码段为代表的权限为可读可执行权限;以数据段和BSS段为代表的权限为可读可写的段;以只读数据为代表的权限为只读权限。

  ELFLinux进程虚拟空间映射关系如下图所示:

 

  即使把多个段(section)合并到几个段(segment),每个段(segment)还是又很能产生较大的页内碎片,怎样解决这个问题呢?Unix巧妙的通过各个段(segment)接壤部分共享一个物理页来解决这个问题。 

参考:http://www.cnblogs.com/zszmhd/archive/2012/08/29/2661461.html、深入理解linux内核、Linux Core Kernel Commentrary、程序员的自我修养。


相关文章推荐

Linux中的地址空间以及I/O地址空间

解惑—Linux中的地址空间(一) 有这么一系列的问题,是否在困扰着你: 1. 用户程序编译连接形成的地址空间在什么范围内? 2. 内核编译后地址空间在什么范围内? 3. 要对外设进行访问,I/O的...

linux下c程序进程地址空间分布

进程地址空间中典型的存储区域分配情况: 从图中看出,从低地址到高地址分别为:代码段、(初始化)数据段、(未初始化)数据段(BSS)、堆、栈、命令行参数和环境变量 堆向高内存地址生长 栈向低内...

Linux虚拟地址空间分布

在多任务操作系统中,每个进程都运行在属于自己的内存沙盘中。这个沙盘就是虚拟地址空间(Virtual Address Space),在32位模式下它是一个4GB的内存地址块。在Linux系统中, 内核进...

一次外场宕机引发对linux内存管理的进一步思考--Linux虚拟地址空间如何分布

这边文章主要从一次宕机事故引申对linux内存布局的思考、对内存分配的思考、对linux保护机制的思考、对swap交换去的思考。...

linux 内核地址和进程地址空间分布

http://www.cnblogs.com/xmphoenix/archive/2011/11/08/2241081.html 内核地址空间分布 直接映射区:线性空间中从3G开始...

转载:地址空间分布

转载自:http://www.cnblogs.com/chengxuyuancc/archive/2013/04/17/3026920.html 地址空间分布   最近看了本书,突然对于地址空间有些疑...

地址空间分布

原文地址:http://www.cnblogs.com/chengxuyuancc/archive/2013/04/17/3026920.html     最近看了本书,突然对于地址空间有些疑...

进程地址空间分布

转载请注明出处:http://blog.csdn.net/wangxiaolong_china   对于一个进程,其空间分布如下图所示: C程序一般分为: 1.程序段:程序段为程序...

[memory]虚拟地址空间分布

一、开篇         踏入嵌入式软件行业也接近2年了,从研一开学起懵懵懂懂的开始学习C语言,由于本科时对这方面了解的少之又少,所以学起来比较困难,但是有一群无私奉献的小伙伴,慢慢的,慢慢的,慢慢的...

linux的VMALLOC虚拟地址空间管理

  • 2015年07月09日 14:15
  • 356KB
  • 下载
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:Linux 地址空间分布
举报原因:
原因补充:

(最多只允许输入30个字)