Unix的分页与现代操作系统分页的作用相反?
时间:2010-08-22 来源:tempname2
这几天看Lions的内核注释,在分页这一块十分纠结。
x86的页表放在内存里,映射地址与选项混在一起成为page descriptor。PDP-11/40专门提供寄存器来做这事,8个寄存器用来映射8页,每个寄存器还配额外的寄存器保存分页选项。一页8K,两个寄存器配合提供一页的映射,一共16的寄存器构成了64K虚拟地址空间。用户态、内核态还各一套这样的16的寄存器。寄存器数量很可观呀。
注释里一会儿称page,一会儿称segment。那个时候的一个page就占了八分之一的虚拟地址空间,叫segment也不为过吧。其实它们都是一小块可以被映射的内存,所谓的分页就是把这一小块内存从某个虚拟地址搬到某个物理地址。8086的分段机的核心思想也是这样的,只不过搬动的是一整个地址空间。这块内存分量大了,就叫segment;分量小了,就叫page。颗粒度不同。
不过,最让人郁闷的是,Unix里的分页机制好像和现代操作系统所使用的分页机制功能相反。以前对操作系统一无所知,看《现代操作系统》,觉得分页这个东西很牛逼,可以把连续的虚拟内存映射到不连续的物理内存。从那以后,分页在我印象中就是做这么个事。带着这个思想去看Unix代码,总觉得不哪里不对头。今天又一次看expand函数,仔细一想,不对呀!代码说,一个进程需要的物理内存本来就是连续分配的。那分页到底在做什么事呢?想了半天,发现Unix里的分页的本质是把不连续的虚拟地址映射到连续的物理地址上!
思考再三,Linux里的分页好像也不是我印象中的那么回事。buddy system提供的也是连续的物理内存。但这些个连续的内存确确实实是可以在页表中被分散到物理内存的各处。嗯,没有总体的观点,说不清楚。。。。。
Unix为一块进程要求text,data,stack空间时得到的是一块连续的内存,也就是说三个区域的内存紧紧接在一起。通过页映射,三个区域在虚拟地址空间中的位置就分开了。text在虚拟地址空间的最底端,比如说占1.5页,那么虚拟地址里的前两个8K都是text的,但第二个8K里只有前4K的地址是有效的,通过该页设置选项寄存器,可以保证引用无效地址时会被CPU拦下来。data则分到了第三个8K,比如说data总大小有2.7K,则第三、四、五个8K都是data的,第五个8K的后0.3K是无效地址。stack则分到了虚拟空间的最顶端,比如说stack总大小有1.3K,则它占第七与、八个8K,也就是虚拟地址空间的最后两页,而且第七个8K的上部分是无效地址,通过对应的选项寄存可以设置成这样。这样,在物理内存中是连在一起的,在虚拟内存中就七零八落了。其中物理内存还为u分配了大小,好像是夹在了text与data中间,映射data的时候,把u跳过去。
起前看Lions举的例子的时候,认为没什么好看的,很不认真。直到实在理解不了了,才又仔细看了一下。自己再举这样类似的例子,似乎更清楚了。expand的代码里,先检查了text,data,stack所占的总页数有没有超过8,接着又检查了text+data+stack+USIZE的大小有没有超过MAXMEM。当时我就纳闷了,检查text、data、stack是否超出8页还不够吗?为什么还要做第二个检查?这直接让我怀疑u到底是分配在哪里了,当我确认无误u是和text、data、stack分配在一起的时候我又纠结了。Lions先生莫名其妙的一句“多出了的八分之一页为u分配”让我觉得检查是否超出页数时是否还要加上u占的一页呢?到底怎么回事?
纳闷了两天以后终于想通了,我连Unix分页到底是在干嘛都没搞清楚,怎么会不迷糊呢?知道了Unix分页是“把连续的物理内存映射到不连续的虚拟内存”后再度思考,一下子就懂了。原来u根本不占虚拟地址空间,所以计算总页数时不需要考虑它。Lions说的“多出的八分之一页”是指多出的八分之一页物理空间!TNND。。。。。data+stack的物理空间加起来正好是4个页。这是物理空间!然而在虚拟地址空间里,2.7页的data要占3页地址,1.3页的stack要占2页地址,加起来要占5页地址。再看Lions举的例子,他已经说了类似的东西!
原来以为懂了的东西其实根本没懂。
x86的页表放在内存里,映射地址与选项混在一起成为page descriptor。PDP-11/40专门提供寄存器来做这事,8个寄存器用来映射8页,每个寄存器还配额外的寄存器保存分页选项。一页8K,两个寄存器配合提供一页的映射,一共16的寄存器构成了64K虚拟地址空间。用户态、内核态还各一套这样的16的寄存器。寄存器数量很可观呀。
注释里一会儿称page,一会儿称segment。那个时候的一个page就占了八分之一的虚拟地址空间,叫segment也不为过吧。其实它们都是一小块可以被映射的内存,所谓的分页就是把这一小块内存从某个虚拟地址搬到某个物理地址。8086的分段机的核心思想也是这样的,只不过搬动的是一整个地址空间。这块内存分量大了,就叫segment;分量小了,就叫page。颗粒度不同。
不过,最让人郁闷的是,Unix里的分页机制好像和现代操作系统所使用的分页机制功能相反。以前对操作系统一无所知,看《现代操作系统》,觉得分页这个东西很牛逼,可以把连续的虚拟内存映射到不连续的物理内存。从那以后,分页在我印象中就是做这么个事。带着这个思想去看Unix代码,总觉得不哪里不对头。今天又一次看expand函数,仔细一想,不对呀!代码说,一个进程需要的物理内存本来就是连续分配的。那分页到底在做什么事呢?想了半天,发现Unix里的分页的本质是把不连续的虚拟地址映射到连续的物理地址上!
思考再三,Linux里的分页好像也不是我印象中的那么回事。buddy system提供的也是连续的物理内存。但这些个连续的内存确确实实是可以在页表中被分散到物理内存的各处。嗯,没有总体的观点,说不清楚。。。。。
Unix为一块进程要求text,data,stack空间时得到的是一块连续的内存,也就是说三个区域的内存紧紧接在一起。通过页映射,三个区域在虚拟地址空间中的位置就分开了。text在虚拟地址空间的最底端,比如说占1.5页,那么虚拟地址里的前两个8K都是text的,但第二个8K里只有前4K的地址是有效的,通过该页设置选项寄存器,可以保证引用无效地址时会被CPU拦下来。data则分到了第三个8K,比如说data总大小有2.7K,则第三、四、五个8K都是data的,第五个8K的后0.3K是无效地址。stack则分到了虚拟空间的最顶端,比如说stack总大小有1.3K,则它占第七与、八个8K,也就是虚拟地址空间的最后两页,而且第七个8K的上部分是无效地址,通过对应的选项寄存可以设置成这样。这样,在物理内存中是连在一起的,在虚拟内存中就七零八落了。其中物理内存还为u分配了大小,好像是夹在了text与data中间,映射data的时候,把u跳过去。
起前看Lions举的例子的时候,认为没什么好看的,很不认真。直到实在理解不了了,才又仔细看了一下。自己再举这样类似的例子,似乎更清楚了。expand的代码里,先检查了text,data,stack所占的总页数有没有超过8,接着又检查了text+data+stack+USIZE的大小有没有超过MAXMEM。当时我就纳闷了,检查text、data、stack是否超出8页还不够吗?为什么还要做第二个检查?这直接让我怀疑u到底是分配在哪里了,当我确认无误u是和text、data、stack分配在一起的时候我又纠结了。Lions先生莫名其妙的一句“多出了的八分之一页为u分配”让我觉得检查是否超出页数时是否还要加上u占的一页呢?到底怎么回事?
纳闷了两天以后终于想通了,我连Unix分页到底是在干嘛都没搞清楚,怎么会不迷糊呢?知道了Unix分页是“把连续的物理内存映射到不连续的虚拟内存”后再度思考,一下子就懂了。原来u根本不占虚拟地址空间,所以计算总页数时不需要考虑它。Lions说的“多出的八分之一页”是指多出的八分之一页物理空间!TNND。。。。。data+stack的物理空间加起来正好是4个页。这是物理空间!然而在虚拟地址空间里,2.7页的data要占3页地址,1.3页的stack要占2页地址,加起来要占5页地址。再看Lions举的例子,他已经说了类似的东西!
原来以为懂了的东西其实根本没懂。
相关阅读 更多 +