1。原理说明



在Linux内核中,采用了适合32位和64位系统的内存分页模型。32位系统,两级页表是不够的,而在x86_64系统,四级页表,如图2-1.the四级页表所示:



*页面全局目录(页面全局目录)



*页面上级目录(页面上级目录)



*页面中间目录(页面中间目录)



*页表(页表)



页面全局目录包含高阶目录地址的几个页面。页面目录包含几个中间目录地址,页面的中间目录包含几个页表地址。每个页面入口项指向一个页框。在Linux,4KB大小的页框作为标准的内存分配单元。



多级分页目录结构



1.1。伙伴系统算法



在实际应用中,一组连续的页框通常是分配的,而频繁的应用和不同大小的连续的页帧释放必然导致许多小自由的页帧散落在分配页框的内存块,这样,即使页面是闲置的,很难满足需要被分配一个连续的页帧的其他应用。



为了避免这种情况,在Linux内核中引入了伙伴系统算法(伙伴系统),所有的空闲页面框都被分成11个块链表。每一块表包含1, 2, 4,8, 16, 32,分别为64128256512和1024连续的页框块,最大可应用于1024个连续的页框,对应的连续内存4MB大小。物理地址的第一页的每一页块的块大小的整数倍。



假设你想申请一个256页块,列表中的256页找到空闲块,如果没有,去512页框列表中查找,找到页框块分为256页的框架2块,一个分配给应用程序,另外一个行动256页框列表。如果在512页帧列表中没有空闲块仍然存在,继续看了1024页的列表框,如果没有,返回的错误。



当块块被释放时,它会主动合并两个连续块块到一个更大的页面块中。



1.2.slab分配器



板坯分配器起源于Solaris 2.4分配算法。它在物理内存页框架分发服务器上工作,管理特定大小对象的缓存,执行快速高效的内存分配。



slab分配器设置每个使用的内核对象的一个单独的缓冲。Linux内核采用伙伴系统来管理物理内存页框,因此slab分配器直接对合伙人制度。每个缓冲区包含一个以上的板,每板是一组连续的物理内存页分为固定数量的对象,根据对象的大小,一个板可以由最多1024页框默认的对齐和其他要求,内存分配给对象的板可能大于用户要求的实际大小,这将造成一定的记忆废物。



2。公用存储器分配函数



2.1。__get_free_pages



无符号长__get_free_pages(gfp_t gfp_mask,unsigned int的顺序)



__get_free_pages函数的内存分配的最原始的方式。它原来的页帧直接从伙伴系统,和返回值是第一页框的起始地址,__get_free_pages实施仅封装在alloc_pages功能。从代码分析,该alloc_pages函数将分配一个长度为1的<<



2.2.kmem_cache_alloc



结构kmem_cache * kmem_cache_create(const char *的名字,size_t大小,



size_t对齐,unsigned long的旗帜,



void(* ctor)(void *,结构kmem_cache *,unsigned long),



虚空(void *(*中签率),结构kmem_cache *,unsigned long))



void * kmem_cache_alloc(struct kmem_cache * C,gfp_t标志)



kmem_cache_create / kmem_cache_alloc是基于板分配的内存分配方法,适用于分布大小相同的内存块重复。首先,创建一个kmem_cache_create缓存区,然后用kmem_cache_alloc从缓存中找到一个新的内存块,kmem_cache_alloc可以一次分配的最大内存是由MM /板max_obj_order宏定义的C文件。在默认的2.6.18内核版本,宏定义为5,所以在大多数时间,它可以申请1 << 5×4KB,这是128KB的连续物理内存,内核源代码的分析发现的bug()被调用时的kmem_cache_create功能尺寸参数大于128KB。试验结果验证了分析结果,和内核崩溃时,kmem_cache_create分配多128kb记忆。



2.3.kmalloc



void * kmalloc(size_t大小,gfp_t标志)



kmalloc是一种最常用的内存分配方法的核心,它是通过调用kmem_cache_alloc函数实现的最大内存大小,kmalloc能够应用于时间的含量测定: / / kmalloc_size Linux。在默认2.6.18内核版本,kmalloc最多只能用一次连续的物理内存的大小131702b或128KB字节。测试结果表明,如果kmalloc函数试图分配内存大于128KB,编译不能通过。



2.4.vmalloc



void * vmalloc(unsigned long大小)



以往的内存分配方法物理上是连续的,可以保证较低的平均访问时间,但在某些情况下,内存区域的请求不是很频繁,更高的内存访问时间也是可以接受的。这意味着我们可以分配一个线性连续的,不连续的物理地址,我们可以把大的块在一个时间。图3-1显示由vmalloc分配的内存使用的地址范围。Vmalloc没有对内存的大小,可以分配一个明确的限制。为了性能考虑,的vmalloc功能应慎用。在测试的过程中,最大可分配1GB空间在同一时间。



linux内核的部分内存分配



2.5.dma_alloc_coherent



void * dma_alloc_coherent(struct装置*开发,size_t大小,



ma_addr_t * dma_handle,gfp_t GFP)



DMA是一种硬件机制,它允许在没有CPU参与的情况下直接在外围设备和主存之间传输IO数据。DMA机制可以显著提高通信设备的吞吐量。DMA操作,包括CPU的高速缓存和内存数据对应的一致性问题,必须保证数据一致性,在x86_64系统结构,硬件是很好的解决这个问题,该dma_alloc_coherent和__get_free_pages功能是不是非常不同,前者是其实叫__alloc_pages函数分配的内存,那么分配内存限制的大小和相同的__get_free_pages分配的内存也可以用于DMA操作。测试结果表明,最大内存分配的一dma_alloc_coherent功能也是4M。



2.6.ioremap



void * ioremap(unsigned long偏移,无符号长尺寸)



ioremap是更直接的记忆分配模式,直接指定的物理起始地址和分配的内存的大小,然后映射物理地址到内核地址空间。用ioremap物理地址空间是事先确定的,并不是上述几种内存分配的方法一样,没有分配一个新的物理内存。Ioremap是用于设备驱动程序,允许CPU直接访问外部设备的IO空间,内存,ioremap可以地图由原来的物理内存空间决定的,所以它不是测试。



2.7.boot记忆



如果我们分配了大量连续的物理内存,并且上述分配函数不能满足,我们只能以相对特殊的方式在Linux内核引导阶段预留一些内存。



2.7.1。在内核引导中分配内存



void * alloc_bootmem(unsigned long大小)



你可以绕过伙伴系统在Linux内核启动过程分配大量的内存,使用方法是将alloc_bootmem函数来指定大小的内存在调用函数时mem_init Linux内核启动。如果你需要调用这个存储在其他地方,你可以导出存储的首地址的alloc_bootmem通过export_symbol回来,然后你可以使用内存,这样的内存分配的缺点是,申请内存的代码必须在代码中使用,与内核。因此,内核必须被重新编译,和内存管理系统看不到这部分内存,这就要求用户管理自己。测试结果表明,重新编译内核重新启动并可以访问分配在开机内存块。



2.7.2。通过内核引导参数保留顶级内存



当Linux内核启动参数MEM = size顶部的内存部分。例如,系统有256MB内存,参数MEM = 248m 8MB内存,并将顶部预留。进入系统后,ioremap(0xf800000,0x800000)可以用来申请内存。



3比较。分布函数的种类



分配原理最大内存



U3000 U3000



分配原则



最大内存



其他

__get_free_pages



直接在页框上操作



4mb



分配大量连续的物理内存是合适的。

kmem_cache_alloc



基于板机制的实现



128kb



适合频繁应用于释放相同大小的内存块。

kmalloc



基于kmem_cache_alloc实施



128kb



最常用的分配模式需要比页框大小更少的内存。

vmalloc



建立不连续物理内存到虚拟地址的映射



物理不连续性,适用于大内存,但不需要地址连续性。

dma_alloc_coherent



基于__alloc_pages实施



4mb



适合DMA操作

ioremap



将已知物理地址映射到虚拟地址



已知物理地址的地方,如设备驱动程序

alloc_bootmem



当内核启动时,内存的一部分被保留,内核不能看到它。



小于物理内存大小,内存管理要求高