linux的内存管理FAQ
一、Linux内存管理到底是分段还是分页?
在实模式下没有引入段式内存管理模式前,程序都是使用绝对地址来进行内存操作的,这样造成了程序的可移植性差等问题。于 是在8086时代开始引入段式内存管理,段式管理引入了地址映射的概念,不但解决了可移植性问题,也解决了16位ALU和段寄存器的可寻址限制,即支持更 大的内存寻址.每个段的大小是64KB.
在实模式下,由于系统程序和用户程序在访问内存等资源时权限没有区分,所以很可能造成操作系统出现异常.于是Intel在80286时代开发出来了保护模式.
而Intel为了兼容80386前的处理器就规定:在IA(Intel Arch)32保护模式下,不能禁止分段,但是分页是Optional的。/*When operating in protected mode, some form of segmentation must be used. There is no mode bit to disable segmentation. The use of paging, however, is optional.*/.
既然linux在内存管理上不能禁止分段,那么linux又认为分段会造成大量的内存碎片,所以就通过将逻辑地址中的段基址置为0,加上偏移量形成线性地址,来简化段式管理内存而使用分页管理内存的。
在IA32下,每页是4K.
二、linux的三种类型内存地址及关系是什么样的?
分段 分页
逻辑地址————> 线性地址 —————->物理地址
在 x86 架构中,内存被划分成 3 种类型的地址:
逻辑地址 (logical address) 由16位段选择符:32位偏移量来表示,它有可能直接对应于一个物理位置(Intel实模式下)。
线性地址 (linear address)或虚拟地址 是由段描述符中的32位段基址和逻辑地址中的32位偏移量相加构成的。例如:0x08048394,由于linux把所有的段基址都置为0x00000000.所以线性地址=0x00000000+偏移量=逻辑地址,在不分页的情况下:线性地址就直接是物理地址;
物理地址 (physical address) 是使用物理地址总线中的位表示的地址。内存管理单元可以将逻辑地址转换成物理地址。
三、为什么在32位的操作系统下每个进程会有4G的内存使用限制?
由于32位操作系统下,由于虚拟地址空间是2的32次方=4 294 967 296,通常的数据对象都以字节为单位,所以一个进程的可寻址范围就是4G内存
四、为什么linux服务器是32位的还可以认出来多于4G的内存?
本来在IA32下,机器只能认出4G的内存,但Intel为了让32位的OS能支持更多的内存。采取了PAE(Physical Address Extension, 物理地址扩展)技术.PAE的支持,不仅需要处理器的支持,OS的内核也需要支持才可行(我们通常采用的RHEL3/4/5 kernel都支持PAE),也就是处理器内部增加了PAE寄存器,用于记录多出的4条地址总线,所以系统就是2^36=64G.
五、在32位的linux操作系统下,为什么linux系统认出来的内存大于4G,而我的程序每个进程却只能分配4G以下的内存?
虽然Intel为其处理器为支持PAE增加了4条地址线,但因为虚拟地址是32位的,所以单个进程还是只能分配4G以下的内存
Note: Linux can use up to 64 Gigabytes of physical memory on x86 systems. However, the address space of 32-bit x86 processors is only 4 Gigabytes large. Thus means that, if you have a large amount of physical memory, not all of it can be “permanently mapped” by the kernel. The physical memory that’s not permanently mapped is called “high memory”.
Redhat网站http://www.redhat.com/rhel/compare/
六、32位的RedHat linux在”smp” kernel和”hugemem” kernel中内存支持方面有什么建议?
Smp kernel和hugemem kernel都支持PAE支持,也就意味着最大能支持64G的内存。而RedHat建议当你的物理内存在16GB之内,用SMP” kernel,在16GB-64GB之间使用”Hugemem” kernel.这是因为虚拟地址空间里有1G用于内核空间,而3G用于用户空间。而关健的一些数据结构是存放在1G内核空间的,在管理32G内存当中,需 要用到0.5G来用于管理这些物理内存(容易触发OOM killer).虽然32位OS下,内核和用户空间的比例都是1:3,但Hugemem打了一个补丁,使比例成为4G:4G,即使内核空间和用户空间相互 独立,所以也会有性能上的损失,因为应用程序的运行,通常会有内核和用户空间的切换。所以如果你的内存大于16G,建议你使用64位的OS。
/* The “SMP” kernel supports a maximum of 16GB of main memory. Systems with more than 16GB of main memory use the “Hugemem” kernel. In certain workload scenarios it may be advantageous to use the “Hugemem” kernel on systems with more than 12GB of main memory. */
七、我们通常malloc了4K内存,到底是怎么对应到物理内存的?
在linux下,处理器在得到内存的线性地址进行内存寻址时,不是直接在内存的物理地址里查找的,而是通过线性地址转换到主内存的物理地 址,TLB(Translation lookaside buffer,可以简单的理解为:一种存储线性地址和物理地址的硬件高速缓冲器)就是负责将虚拟内存地址翻译成实际的物理内存地址,而CPU寻址时会优先 在TLB中进行寻址。如果TLB里没有,则从页表里进行线性地址到物理地址的转换.hugepage能增加TLB的命中率,所以会在某些方面能大大提高系 统性能)。
1、逻辑地址转线性地址
a、首先根据指令的性质来确定该使用哪一个段寄存器。
b、根据段寄存器的内容,到GDT中找到相应的“段描述结构”
c、根据linux把所有的段基址都置为0×00000000.所以0×00000000+偏移量就是线性地址了.在不分页的情况下:线性地址就直接是物理地址;
同时,在上面过程中,由于有对访问权限的检查,就实现了保护。
2、线性地址转物理地址
在保护模式下,控制寄存器CR0的最高位PG位(PE位控制是否为保护模式)控制着分页管理机制是否生效,如果PG=1,分页机制生效,需通过页表查找才能把线性地址转换物理地址。如果PG=0,则分页机制无效,线性地址就直接做为物理地址。
页式内存管理中,32位的线性地址划分为三个部分:10位的页目录表下标、10位的页面表下标、12位的页内偏移量。CPU增加了一个CR3寄存器存放指向当前页目录表的指针。寻址方式就改为:
a、从CR3取得页目录表的基地址;
b、根据10位页目录表下标和从CR3取得的基地址,得到相应页表的基地址;
c、根据10位页面表下标和b中得到的页表基地址,从页面表中取得相应的页面描述项;
d、将页面描述项中的页面基地址和线性地址中的12位页内地址偏移相加,得到物理地址。
同时,在地址转换的过程中也有越界和权限的检查,就不赘述了。
注:传统的32位操作系统采用的是两级分页模型
64位和PAE支持都采用了三级分页模型