[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
很好的文章,学习了
其中用户态使用前3G,内核态使用最后1G??? 为什么呢?请问有没有全面描述linux内存操作的资料呢,我是指原理性的,谢谢。
《深入理解linux内核》
这就是为什么不建议,小内存机器用x86_64的原因,
上次一个老的机器,装了一个N卡的驱动,
换个内核启动,这个时候,N卡的这个没有匹配好内核的驱动
通过 DMA32 啃光我4G内存!
@joker,很好的例子,受教了