其实我觉得操作系统的内存管理很神秘,且不说在写应用程序时调用的malloc,在写linux驱动时get_free_page,get_free_pages,kmalloc,就相当头疼。看完linux0.11之后小有感触,就此记下。
先说内核使用的get_free_page吧,其实get_free_page返回的是空闲页面的物理地址,见下图所示
物理内存被分割为一般大小为4kb的页面,在内核中有一个与总页数大小相同的数组,数组对应项中保存着对应页面的一些基本信息,如是否被占用,读写的权限,共享等。
get_free_page函数就是在此数组中寻找一个没有被使用的页面,然后标记为在使用,然后返回该页面的物理内存地址。没错就是物理地址,你学过操作系统,一般是不会使用物理地址,一般物理地址都是线性地址通过页面就行转换得来的,确实内核也不例外。先埋伏笔于此。
在linux0.11中内核的代码段和数据段的限长为16MB,linux0.11所能管理的最大内存也就是16MB,所以内核能对每一块内存访问。内核有四个页目录项,总共映射16MB的内存。
总结一句就是在内核中,任何一个线性地址经过页表转换,得到的物理地址和线性地址是一样的(因为原因如上图所示,内核对自己限长内的16MB都映射为与线性地址相同的物理地址,图画的不是很好,见谅)
所以当get_free_page返回物理地址时,内核可以直接使用物理地址作为指针,访问对应的物理内存,因为物理地址和线性地址是一样的。了然?
kmalloc其实返回的也是物理地址,如上在内核使用时直接使用,访问对应物理内存,只不过它采用了一种机制,在内核中分配指定大小的物理内存。使用的是存储桶原理
具体的实现我就不说了,网上有很多推荐一篇malloc存储桶原理
在用户程序中使用的malloc是用户的函数库提供的,基本原理就是最终会调用系统调用brk,增加数据区的大小,但并不在此时分配实际的物理内存,在实际调用使用的时候出现缺页异常的时候分配内存,增加页表项。
说了这么多,理解内核分配的要点就是内核页面中线性地址被映射到相同数值的物理地址,内核中物理地址和线性地址可以混用,对于内存的管理相当方便。