[kernel] x86_64的内存管理

ULK3上花了不少力气讲解32位x86机器的内存分区(zone)的原因和现状,可能很多人都看熟了,物理内存被分为三个zone:

ZONE_DMA
ZONE_NORMAL
ZONE_HIGHMEM

ZONE_DMA是为了给一些外设硬件保留的,是0~16MB,ZONE_NORMAL是从16MB~896MB,ZONE_HIGHMEM(高端内存)负责896MB以上的物理内存。当然,如果物理内存本身就小于896MB,那么就没有ZONE_HIGHMEM(高端内存)区了。
为什么边界是896MB?为什么会有一个“高端内存”?我擅自给个粗俗的解释:
大家都知道32位linux上的虚拟地址空间是4G(CPU最多能访问这么大),其中用户态使用前3G,内核态使用最后1G,但是内核必须能够访问整个物理空间(直观想一下,这样驱动才能够为所欲为),可是万一内存条大于1G了,就不能完整的将物理内存映射到这个可怜的1G虚拟空间(显然不够),那怎么办,于是发明了这个“高端内存”的概念。假设机器上装了2G的内存条,那么内核只把内存条上的896MB直接映射到内核态去,这下,内核的虚拟地址空间也只剩下128MB了(总共才1G),剩下的1G零128MB的物理内存怎么办?这样,内核什么时候需要,就什么时候把这些剩下的物理内存映射到那128MB虚拟地址空间上,这就叫临时映射,用的是kmap。当然,这128MB虚拟地址空间一次也只能映射128MB的物理地址空间,想要访问另外的物理空间,只能用kunmap把这一映射取消,再kmap重新映射另外128MB的物理地址......按需临时分配,很罗嗦很烦人,效率也不高。


这一别扭设计的根源在于——32位的地址空间太小了,所以,赶快升级64位吧。
到了x86_64体系下,地址空间就大多了,不用这么别扭了。在x86_64体系下,用户态和内核态各有多大的虚拟地址空间呢?看下图,一目了然。为什么是这样?参考维基百科


现在既然虚拟地址空间这么充裕,就不需要再使用ZONE_HIGHMEM了(还在啃ULK3上这部分内容的同学,抛开它吧!),kmap操作也变成直接返回页面地址。x86_64上的物理内存分三个zone:

ZONE_DMA(这个是为了外设,必须保留)
ZONE_DMA32 (这个还是为了一些特殊硬件,参考作者的解释
ZONE_NORMAL

如果有x86_64的机器,大家可以

cat /proc/zoneinfo

看到这三个区各自的参数。

Node 0, zone    DMA32
  pages free     634082
        min      1159
        low      1448
        high     1738
        scanned  0
        spanned  1044480
        present  833504

喏,这就是ZONE_DMA32的情况,总共用了833504个物理页面,其中634082个物理页面空闲,这里还能看到著名的page_low%P縄POST /cgi-bin/blog/mt.cgi HTTP/1.1 Host: www.baidu.com Connection: keep-alive Referer: http://www.baidu.com/cgi-bin/blog/mt.cgi?__mode=view

5 Comments

问题 said:

很好的文章,学习了

陈祖飞 said:

其中用户态使用前3G,内核态使用最后1G??? 为什么呢?请问有没有全面描述linux内存操作的资料呢,我是指原理性的,谢谢。

DongHao Author Profile Page said:

《深入理解linux内核》

joker said:

这就是为什么不建议,小内存机器用x86_64的原因,
上次一个老的机器,装了一个N卡的驱动,
换个内核启动,这个时候,N卡的这个没有匹配好内核的驱动
通过 DMA32 啃光我4G内存!

DongHao Author Profile Page said:

@joker,很好的例子,受教了

关于文章

This page contains a single entry by DongHao published on 11 11, 2010 11:38 AM.

水土不服 was the previous entry in this blog.

来,纸上谈谈兵 is the next entry in this blog.

Find recent content on the main index or look in the 存档 to find all content.