0xc0000000128MB8MBpagetable_init()RAM896MB0xc00000001G,送去最后的128MB剩下896MBRAMRAM大小在896~4096MB之间时,内核只能根据页表寻址到其中的896MB,初始化阶段就将896MBRAM128M0xc0000000,而可以任意建立。不论如何RAM某些部分已永久给内核,剩下的叫动态内存。
80x86DRAMSRAM间传送数据以实现调整缓存。直接映射时,主存的一行就是cache中相同位置的一行,充分关联时,主存中一行可存于cache中任意一行,NcacheN行中任一行。Cache控制器的表项数组中的表项有一标签,通过这若干位的标签识别物理内存单元。物理地址的高几位用于标签,中间用作cache控制器的子集索引,低几位用于提出行内偏移量。访问一RAM时,CPUCacheDRAM地址中根据规则提出信息,根据信息去SRAM中找数据,免得每次对DRAM pagemem_map32cpu访问不同内存是否花时间不同决定。若是非一致的情况,则将物理内存分为若干节点,节点范围内部访问时间相同。每节点在内核中有对应的数据结构pg_data_t描述符。但它们不以数组组织,以链表串起来。虽然80x86体系结构使用一致访问,但Linux 80x861.ISADMA处理器只可对RAM前16MBI/O24位);2.大容量RAM4G的线性空间使得不可直接访问所有RAM,为解决这问题,Linux380x86ZONE_DMA16MBRAMZONE_HIGHMEM896MBZONE_NORMAL >128&&<65535。ZONE_DMA与ZONE_NORMAL区各将一定数量页框献出来作保留页框。对于每个内存管理区,有三种主要的内存分配形式:
一、它由内核子系统“分区页框分配器”处理。其中的“管理区分配器”完成动态内存的分配与释放。请求页框有适当的函数与宏,它们的参数可指出搜索管理区的顺序。请求成功则返回对应的线性地址,问题来了,对ZONE_HIGHMEM的请求成功如何返回呢?线性地址映射前896M128M128MB)的关系。分配成功后返回的是页描述符的指针,根据它到一个hash表中,找出最终的映射结果,即线性地址。如果其它情况的映射,但在高端内存已无空页时会引起阻塞,所以在软硬中断中不可行。临时映射,不会要求阻塞,相反它要求不能阻塞,因为怕其它内核控制路径用同一窗口来映射其它高端内存。不论哪种技术都不可同时对整个RAM寻址。对于临时内核映射,高端内存任一页框可以通过一个“窗口”(为此保留的一个页表项)映射到内核地址空间。每个CPU都有自己的13解决了怎么分配,接下来考虑分配策略。由于分配连续的页框,若策略不好会产生大量外碎片。解决外碎片的常见两种思路是将不连续的空页框映射到连续的线性地址或允许一种技术尽量提高分配效率。考虑到如老式DMA等服务需要连续页框且连续的页框可提高牛快表特性,一般都会第二种方法。Linux用伙伴系统来解决外碎片。它将所有空闲页框分为11个块链表,每个链表串起12、4……10241024个页框充满了一个页表(1024C++中STLvector所有内核申请页框操作的最上层是“管理区分配器”,它负责保护保留的页框池,内存不足且允许阻塞时引发页框回收算法,并尽可能保存小而珍贵的DMA区。
二、Linux使用的是返回内存大小是250%SunSolaris2.4slabobjectSlabslab分配器把那个页框存在高速缓存中。
Slab分配器将对象分组放入调整缓存,包含调整缓存的主存分为多个slab,每slabslabslabslabslab描述符之后(如果slab描述符本身存在slabSlab三、0xc0000000开始的1G896M的映射,最后是固定映射与永久内核映射的线性地址。它们中间的可用于非连续内存。在物理映射末与第一内存之间加入8MB的安全区用于捕获越界访问。同样,在区与区之间插入4K大小安全隔离带。非连续内存区也有对应的描述符。分配时先分描述符,找线性地址区间。之后再分页框,将分得的不连续页框的页描述符存在area->pages数组中,最后再更新内核使用的页表项。
__get_free_pages()alloc_pages()kmem_cache_alloc()kmalloc()slab分配器为专用或通用对象分配块;vmalloc()或vmalloc_32()获得非连续内存区。可使用如此直接的步骤是因为内核是OS中优先级最高的部分。若某内核函数请求动态内存,不会推迟,且内核函数被认为是正确的,这就不用出错处理了。