在基于arm的平台系统(linux)中,一个可执行程序被加载到内存后就成为一个进程。而我们的内存这时就充当这些进程的舞台,进程在内存中就可以畅快的执行。但是我们知道在嵌入式系统中,内存一般都比较小,这些都是受体积、成本、功耗等因素的制约导致的,所以这就带来一些问题:
1、当要执行某个进程时,由于内存小所以容纳不下该进程所有的代码、数据、堆栈等。
2、对一个可同时运行多个进程的系统而言,如果其中某两个或多个进程所运行的空间有重叠的话,那它们将无法同时运行,因为它们中的其中一个的改变都会破坏其它进程的内存内容。
为了解决这样的问题,这时内存管理的概念被提了出来,而其中的内存管理中的页置换就可以很好的解决上面出现的问题。页置换的理念就是当要加载某个可能会占用大量内存的进程时,在当前时段它只会使用代码段、数据段、堆栈段等一小部分。基于这样的理念,我们每次在需要其它的代码段等等数据时就可以从我们存储的磁盘(如flash)中加载需要的代码而置换出内存中暂时不需要的代码,而如何置换又有另一套置换算法,这里暂不说了。
根据上面提到的理念,我们可以看到这样一个os,在具体的某一时间段中只加载需要的代码到内存中,剩余的保存在磁盘中。当要使用到不在内存中的代码时,就通过置换算法置换出内存的不需使用的代码,加载进磁盘中的代码。但是还不够完善,因为我们再回头看看上面的第二点,进程空间的重叠问题并没有解决。那这个问题是否有什么好的办法来解决呢?
为了解决重叠问题,我们请出”重量级选手“--虚拟内存。所谓虚拟内存,它是相对于物理内存而言的,字面理解,就是不存在的,虚构出来的。这里我们根据32位地址线来讨论。我们知道对于包含MMU(内存管理单元)的处理器而言,linux系统提供了复杂的存储管理系统,也就是我们这的虚存,它使得进程所能访问到的地址空间达到4GB。至于这个4GB又是被划分成两部分:用户空间(0-3GB)和内核空间(3GB-4GB)。意思就是用户空间只能访问用户空间的虚拟地址,要想访问内核空间只能通过系统调用这种方式间接访问。内核空间的1GB又被划分成不同的区域,这不是今天讨论的话题,留待以后再说。
说这么多其实就是想告诉我们虚拟内存存在的价值就是在我们编译app时,这个app的地址空间是虚拟地址空间,不信?下面实验说话:
上面是两个差不多的一段简单程序以及它们的编译,接下来我们要通过arm-linux-objdump -d helloworld1/helloworld2,这里反斜杠分开表示每个命令输入一遍,来查看它们的反汇编结果,来查看这段程序所用到的地址空间。我们取其中的main()函数部分来看。
这里第一列83e8、83ec...就是运行的地址(虚拟地址),第二列e92d4800...等是机器码,最后两列就是汇编代码。我们对比这两个结果可以看出这两个可执行程序的地址空间是重叠的,但是当我们运行时并没有发生冲突,这就是虚拟内存给我们带来的好处。
其实每个进程的用户空间都是完全独立、互不相干的,用户进程有各自的不同的页表。而内核空间是由内核负责映射,并不会跟着进程改变,是固定的。内核空间地址有自己对应的页表,内核的虚拟空间独立于其它程序。再看我们这里的两个程序,它们是相互独立、互不影响的,只是当这两个程序被加载到内存时,我们的MMU又会将它们映射到不同的物理地址空间中,这样它们二者就可以同时运行而又避免互相影响了。
阅读(672) | 评论(0) | 转发(0) |