讨论一下多任务虚拟内存管理

最近看了QNX文档中关于MMU说明,有一些疑问想和大家讨论一下。
在文档中讲到了QNX把物理内存以4k为单位进行虚实地址的映射,并且为每一个进程都分配独立的地址空间,并且说每一个进程有独立的MMU的页表集,这样在上下文切换的时候使用不同进程的页表集。而每一个进程都有0-3.5G的地址范围,那么光为一个进程的页表集分配的内存空间就要耗掉4k-8k。
如上所述,我的问题是:
在QNX系统中的进程的个数限制是多少呢???
那么在启动每一个进程的时候的系统为他的虚拟地址是怎么分配的呢???
如果安照每一个进程一个页表集的分配方式,是不是太消耗内存了呢???

如果有谁关心过这块的,说两句吧!

每一个进程“最大”可以有3.5G的地址空间,但并不是每个进程都会用到那么多的。进程要通过mmap()来取得地址空间,系统只在这时候才修改页表。你在"pidin mem"里看到进程占了多少内存,/4k就是页表项数了。

顺便提一句,如果你的程序读写了一个“非法地址”,系统之所以会知道并crash你的程序,就是因为在页表里找不到对应的页表项。:slight_smile:

QNX中同时可以运行的进程个数是 4095

系统为进程分配虚拟空间有一个的内部规律,(代码总是在哪里,堆栈从哪里开始等等)根据平台不同略有差异。

好的,先谢谢xtang的解答。我还是有问题想再问一下:
您说,进程要通过mmap()来取得地址空间,系统只在这时候才修改页表。
但是我想一个进程在执行指令或访问本进程的数据的时候是不用mmap()的吧,那么进程给出的虚地址在转化成物理地址的时候要用到一份映射表集,是不是如文档所述,每一个进程使用了不同的MMU页表集???

如果所有进程使用各自独立的不同的页表集,那么据我在看s3c2410中MMU的资料所知,一级表中至少要有1024个页表项(因为即使对应的物理地址为空也有一个表项来描述),也就是光这个一级表就要有4K的内存空间。那么4095个进程肯定就会好掉很多的内存???

如果所有进程使用相同页表集,那么系统是不是要保证各个进程的的逻辑地址空间不相互重叠呢???

将问题总结一下: 系统在进行上下文切换的时候是使用的同一份页表集(也就是对应关系映射表),还是要切换到另一个映射表???

一个进程,原来在硬盘上。当它被加载进内存的时候,进程管理器根据ELF头,决定为它分配多少多存(代码占多少,HEAP占多少,堆栈要用多少),加载完毕以后,进程的页表就决定了。(比方在10000 有3面堆栈,在20000有5页代码…)

这个页表,每个进程有一个;当切换到一个进程时,它的页表被载入MMU;

进程执行指令,访问数据,只是参照页表。你读写10004,MMU会去查页表找出对应的物理地址。(MMU当中还有一个CACHE的问题,先假设没有CACHE的情况)如果你读写15000,MMU在页表里找不到这个虚拟地址的对应,就报错。整个的过程,进程的“地址空间”不发生变化,所以页表不会变化(增多或减少)。

只有当进程mmap()/unmap() (malloc()/free()最后也可能落到一个mmap上)时,进程的“地址空间”才会变化。(多了一块或是少了一块地址)这个时候,进程的页表会被修改。

啊,ARM有特殊情况。:D:D 简单来说在ARM上,只有63个进程,每个进程只有32MB空间。

在Neutrino Programmer’s Guide里,专门有一个附篇讨论ARM的情况。我自己对ARM的MMU设计不是完全清楚,不过你可以参考一下这个附篇。特别是
Implications of the ARM Cache Architecture这个部份。

http://www.qnx.com/developers/docs/6.3.0SP3/neutrino/prog/arm_memory.html

通常是不同的页表。(ARM7 ARM9特殊,ARM11好象限制又不一样)。

好的,谢谢xtang! 还有一个问题想问一下:
关于mmap()/mmap_device_memory()函数, 如果我要把一块物理地址映射到进程的地址空间的时候,如果给定的物理地址实际上不存在,那么会不会映射成功呢???
我试了一下,可以映射成功的,并且映射得到的虚拟地址进行数据读写都是可以操作的,只是值为0xFFFFFFFF而已。觉得挺奇怪的,难道QNX系统不管实际的物理地址是否存在的吗???
如果真是如我上面所述QNX系统不管实际的物理地址是否存在的话,那么我不就是可以把每一个进程都占满3.5G的虚拟地址空间了喽???这样的话我觉得MMU的所需要的映射表肯定就要占去很大的一块内存,那么肯定跑不了多少个进程吧??? 困惑中???

映射可以成功。因为那个物理地址上可能有硬件寄存器。在non-x86的平台上,硬件寄存器是同Memory一样读写的。

你可以用程序mmap(),耗费大量的地址。如果你启动大量这样的程序的话,最后当然可能造成没有内存放页表,使你的mmap()失败。其实,如果一个进程mmap()了大量内存的话,很可能第二个进程根本就无法载入内存。

最后顺便提一句,3.5G是x86的情形,别的平台不一样,相对少一点。