+ -
当前位置:首页 → 问答吧 → Linux内存线性地址空间布局解析---的一些疑惑,大家帮忙解释解释

Linux内存线性地址空间布局解析---的一些疑惑,大家帮忙解释解释

时间:2010-08-07

来源:互联网

本帖最后由 unbutun 于 2010-08-07 08:25 编辑

下载 (38.96 KB)
2010-08-07 07:59




Linux内存线性地址空间大小为4GB,分为2个部分:用户空间部分(通常是3G)和内核空间部分(通常是1G)。在此我们主要关注内核地址空间部分。

内核通过内核页全局目录来管理所有的物理内存,由于线性地址前3G空间为用户使用,内核页全局目录前768项(刚好3G)除0、1两项外全部为0,后256项(1G)用来管理所有的物理内存。内核页全局目录在编译时静态地定义为swapper_pg_dir数组,该数组从物理内存地址0x101000处开始存放。

由图可见,内核线性地址空间部分从PAGE_OFFSET(通常定义为3G)开始,为了将内核装入内存,从PAGE_OFFSET开始8M线性地址用来映射内核所在的物理内存地址;接下来是mem_map数组,mem_map的起始线性地址与体系结构相关,比如对于UMA结构,由于从PAGE_OFFSET开始16M线性地址空间对应的16M物理地址空间是DMA区,

-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
问题1、既然PAGE_OFFSET+8M开始的地方已经放了内核的image了,那PAGE_OFFSET+16M怎么又对应16M物理内存空间了,用于DMA了?
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

mem_map数组通常开始于PAGE_OFFSET+16M的线性地址;从PAGE_OFFSET开始到VMALLOC_START – VMALLOC_OFFSET的线性地址空间直接映射到物理内存空间(一一对应影射,物理地址<==>线性地址-PAGE_OFFSET),这段区域的大小和机器实际拥有的物理内存大小有关,这儿VMALLOC_OFFSET在X86上为8M,主要用来防止越界错误;在内存比较小的系统上,余下的线性地址空间(还要再减去空白区即VMALLOC_OFFSET)被vmalloc()函数用来把不连续的物理地址空间映射到连续的线性地址空间上,
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
问题2、这块前面(一一对应影射,物理地址<==>线性地址-PAGE_OFFSET)把物理内存都映射到了PAGE_OFFSET开始到VMALLOC_START – VMALLOC_OFFSET的线性地址空间,那后面(被vmalloc()函数用来把不连续的物理地址空间映射到连续的线性地址空间上)是在做什么,前面已经映射了一次,后面还映射一次不是重复了吗,为什么前面要映射所有的物理内存,那我直接访问前面和访问后面是不是一样的,主要是不明白为什么要这样做,总感觉这有点模糊?
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------


在内存比较大的系统上,vmalloc()使用从VMALLOC_START到VMALLOC_END(也即PKMAP_BASE减去2页的空白页大小PAGE_SIZE)的线性地址空间,此时余下的线性地址空间(还要再减去2页的空白区即VMALLOC_OFFSET)又可以分成2部分:第一部分从PKMAP_BASE到FIXADDR_START用来由kmap()函数来建立永久映射高端内存;第二部分,从FIXADDR_START到FIXADDR_TOP,这是一个固定大小的临时映射线性地址空间,(引用:Fixed virtual addresses are needed for subsystems that need to know the virtual address at compile time such as the APIC),在X86体系结构上,FIXADDR_TOP被静态定义为0xFFFFE000,此时这个固定大小空间结束于整个线性地址空间最后4K前面,该固定大小空间大小是在编译时计算出来并存储在__FIXADDR_SIZE变量中。

正是由于vmalloc()使用区、kmap()使用区及固定大小区(kmap_atomic()使用区)的存在才使ZONE_NORMAL区大小受到限制,由于内核在运行时需要这些函数,因此在线性地址空间中至少要VMALLOC_RESERVE大小的空间。VMALLOC_RESERVE的大小与体系结构相关,在X86上,VMALLOC_RESERVE定义为128M,这就是为什么ZONE_NORMAL大小通常是16M到896M的原因





问题3、这里VMALLOC_START 是固定的大小还是,会变?就是编译时就定死了,还是根据物理内存啥的算出来的?


问题4、这么映射物理内存,那么物理内存是4G,或者大于4G怎么办?

作者: unbutun   发布时间: 2010-08-07

本帖最后由 Tinnal 于 2010-08-07 13:26 编辑

回复 unbutun

-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
问题1、既然PAGE_OFFSET+8M开始的地方已经放了内核的image了,那PAGE_OFFSET+16M怎么又对应16M物理内存空间了,用于DMA了?
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
答:其实PAGE_OFFSET+16M就是mem_map数组,这个数据是全部内存的page结构体,不仅16M这么少。内存会把PAGE_OFFSET到VMALLOC_START – VMALLOC_OFFSET的内存按使用的功能来分区。那为什么有16M用于DMA这种说法呢。其实这不是软件没事做瞎搞。例如,我们向伙伴系统申请一段8K的空间,内存系统其实是可以把两个不连续的叶(每个4K)通过MMU,映射成连续的然后返回给我们,当然,对软件而言,这就是连续的,但对硬件呢,例如网卡,他想返回8K数据给我们应用程序怎么返回,一种(中断方式或轮训方式)情况:我们的程序读网卡寄存器(当在也是映射后的地址)把读到的数据存到刚才分配的空间; 另外一种是DMA,应用程序把内存的起始地址给网卡,网卡会拿下总线,不管CPU(包括在CPU内的MMU)而去直接操作内存。问题来了!这8M在物理上是不连续的,网卡只知到一个起始地址和长度。那怎么搞!这就是DMA区的作用,在DMA区分配的内存,在物理上是连续的,以DMA设备使用。当然,要连续,就很难管理,所以只有16M。驱动编写人员要好好珍惜,不要什么需求都申请DMA区域的。   

此外,你的前半句和后半句没有什么必然联系,我想你把一件事搞糊涂了,就是内存分配代码在内核里,内核又要内存分配系统分配内存,好像是互相包含。其实伙伴系统在生效前,还有一个bootmem的临时内存管理办法。在伙伴系统初始化时,会把自身和内核占用的内存标志为保留(和被分配出去一样),这样,我们就可以说,内存管理系系统管理者包括内核(PAGE_OFFSET+8M)和自身(PAGE_OFFSET+16M)在内的全部内存(包括16M的DMA区域),自已管自己?没什么不可能,鸡生鸡:)

作者: Tinnal   发布时间: 2010-08-07

4g和小于4g一样处理的好像.大于4g就开启PAE,多一级页目录,页表中存放36位物理地址.系统总可调度的物理内存空间最大可达64G,但因为线性地址仍然是32位,所以每进程可用的内存仍然不会大于3G,

作者: liwangli1983   发布时间: 2010-08-07

回复 unbutun


-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
问题2、这块前面(一一对应影射,物理地址<==>线性地址-PAGE_OFFSET)把物理内存都映射到了PAGE_OFFSET开始到VMALLOC_START – VMALLOC_OFFSET的线性地址空间,那后面(被vmalloc()函数用来把不连续的物理地址空间映射到连续的线性地址空间上)是在做什么,前面已经映射了一次,后面还映射一次不是重复了吗,为什么前面要映射所有的物理内存,那我直接访问前面和访问后面是不是一样的,主要是不明白为什么要这样做,总感觉这有点模糊?
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

“物理地址<==>线性地址-PAGE_OFFSET”的区域只有896M,就算我不占用后面的128M,最多这个区域也只有1G,这最极限没办法,是由LINUX的3:1模型决定的,那如果内存大于1G呢??晕,内核用不了!因此,留下128M,不做前896M这种连续映射的“啥事”,要用那块剩下的物理内存了,拿点128M内的虚拟地址来映射,用完还回去,以便一次用来映射别的空间。

作者: Tinnal   发布时间: 2010-08-07

回复 unbutun


问题3、这里VMALLOC_START 是固定的大小还是,会变?就是编译时就定死了,还是根据物理内存啥的算出来的?
这是代码写死的,要改,去改代码去吧。但对4G和大于4G的情况认像中好像有不同值。


问题4、这么映射物理内存,那么物理内存是4G,或者大于4G怎么办?
这个不但软件没有办法,如果不更新技术,CPU和MMU也没有办法,所以现在有PAE技术,也就是大页(每页大于4K,认象为2M)


全部问题答完,鹅做了两年应用,内核忘得差不多,有错即改。

作者: Tinnal   发布时间: 2010-08-07



QUOTE:
回复  unbutun

---------------------------------------------------------------------------------- ...
Tinnal 发表于 2010-08-07 13:06




    PAGE_OFFSET+8M PAGE_OFFSET+16M我的问题是既然 PAGE_OFFSET+8M用于存放内核代码,那么PAGE_OFFSET+16M这个区域就包含了PAGE_OFFSET+8M,
如果PAGE_OFFSET+16M还用于DMA,那么PAGE_OFFSET+8M就相当于被覆盖了,对吧?

作者: unbutun   发布时间: 2010-08-07

哥们,谢谢你回复,不过你好像也没太理解内存管理,我的问题都被你搅乱了


还是哪位对内存管理真正通的高手来帮帮忙吧?

作者: unbutun   发布时间: 2010-08-07

热门下载

更多