Linux虚拟内存概述

为什么需要虚拟内存?


程序是一系列代码段,数据段的集合,而程序要运行必须是加载到内存里的,但是物理内存就那么大,如何能保证很多个程序都装载进去呢?这里就引进了虚拟内存的概念,虚拟内存基本思想就是,给每个程序都分配一个4G的虚拟的内存,但这部分内存占用的不是物理内存,而是磁盘空间,这部分叫做虚拟存储器,就是安装Linux系统时候的SWAP空间。而对应的物理内存就是物理存储器。
有没有觉得整个过程像开了“空头支票”一样?程序要跑起来,操作系统许诺它给你4G的空间,但却是不能用的,那真要执行的时候怎么办呢?操作系统会把磁盘上的程序代码数据“移”到内存里,把不需要的还会“移”出去到磁盘上,这样看上去就好像可以跑很多进程了。

怎么实现虚拟内存


首先是段机制,程序从程序员看被分成了很多段,链接的时候都会把段组织好,各个地址的设置(地址都是虚拟地址),然后加载器加载。接下来就是按需要从虚拟存储器换入到物理存储器了,怎么换合适?一个段一个段换?这个一看就是很笨重的,段可能很大呢?还有段的换出呢?还有导致物理内存碎片很大。于是就引入了页的概念,页的实现就是说把虚拟内存和物理内存都分成一个一个页,就理解成一个线性数组(里面都是字节)进行切割,每个页是很多字节的集合。页不能太大,太大的话内部碎片会很大;也不能太小,太小导致维护成本很高。一般都是4K,结合上面的虚拟内存,所以虚拟存储器和物理存储器的进程的换入换出都是以页为单位进行的,叫做换页。

什么时候换页?


先看何时?首先是换入,CPU执行着发现所需要的页不在内存里,这时候就会产生缺页中断,对应的中断程序会把相应的页换入内存,然后继续执行原来的指令,整个过程对于程序是完全透明的。再是换出,换出就是内存紧张了,不够用了就换出。那把什么页面换出呢?一般都是采用LRU(Least Recently Used)算法。

怎么实现换页?


上面说了,要实现换入换出,起码操作系统得知道物理存储器和虚拟存储器上一个进程对应的页分配情况吧?还有如何保证A进程的物理页和B进程的物理页不重复呢?(先这样说着,还有很多情况是可以重复的,比如共享库,fork开始的时候等等)这就是说A的页映射函数和B的映射函数不一样了?这里引进页表的概念,页表就相当于是上面的映射函数,进程的虚拟页到物理页的映射关系都存储在这里。页表是存在内存里的,每个进程都有自己的一份页表,操作系统页有自己的一份页表。页表每项都会有一个标志位P,指明了这张页是否存在内存里。

虚拟内存

对于一张页,每个页表项可以是下面的,

P : 对应项	==>>  物理意义
0 : NULL  	==>>  请求的页不在物理内存中,但是对应指针是NULL,代表还没分配。
0 : 磁盘页地址	==>>  请求的页不在物理内存钟,但是对应指针不是NULL,表示已经分配,比如malloc出来的地址,已经分配虚拟页,但不是物理页。
1 : 物理内存地址  ==>>  请求的页在物理内存中,且这个页表项还有对应页在物理内存中的基地址。

总结下,Linux下的页机制和虚拟内存配合的十分巧妙,虚拟内存也是一个抽象的实现。

标签:Linux, OS, Kernel

评论已关闭