- 论坛徽章:
- 0
|
本章分三部分讲解内核如何给自己分配动态内存dynamic memory。
连续物理内存区(页框管理、内存区管理),非连续内存区(非连续内存区管理)。
主要涉及内容:内存管理区、内核映射、伙伴系统、slab高速缓存和内存池。
RAM的某些部分永久分配给内核,存放内行代码和静态内核数据结构。RAM其余的部分称为动态内存。
1. 页框管理
涉及数据结构:
页描述符struct page、节点描述符、管理区描述符、管理区描述符指针数组zonelist
页框的状态信息保存在类型为page的页描述符中。
所有的页描述符存放在mem_map数组中。
macro: virt_to_page(addr) pfn_to_page(pfn)
NUMA中,物理内存被划分为几个节点node。一个单独的节点内,任一给定CPU访问页面所需时间相同。每个节点都有一个类型为pg_data_t的描述符,所有节点的描述符存放在链表pgdat_list中。
UMA模型中,虽然对NUMA的支持没有编译进内核,linux仍然使用节点,不过只有一个节点,它包含了所有的物理内存。80x86中这样处理是为了可移植性。
每个节点的物理内存又可以划分为3个内存管理区zone。
在80x86 UMA体系结构中为:ZONE_DMA ZONE_NORMAL ZONE_HIGHMEM
其中,ZONE_DMA和ZONE_NORMAL,通过线性映射到线性地址空间的第4个GB,内核就可以直接访问。
ZONE_HIGHMEM包含的内存页不能由内核直接访问,尽管它们也线性映射到线性空间的第4个GB。
64位体系结构上ZONE_HIGHMEM区总是空的。
每个zone都有自己的管理区描述符,其中
unsigned long free_pages字段是管理区中空闲页的数目,
struct free_area[] free_area字段标识出管理区的空闲页框块(伙伴系统算法)
The Pool of Reserved Page Frames
The Zoned Page Frame Allocator分区页框分配器
图中的管理区分配器(Zone allocator)部分接受动态内存分配和释放的请求。
alloc_pages(gfp_mask, order) 返回第一个页框描述符地址
alloc_page(gfp_mask)
__get_free_pages(gfp_mask, order) 返回第一个页的线性地址地址
__get_free_page(gfp_mask)
get_zeroed_page(gfp_mask) 返回线性地址
__get_dma_pages(gfp_mask, order)
__free_pages(page, order) page指向页描述符
free_pages(addr, order) addr为线性地址
__free_page(page)
free_page(addr)
与高端内存的始端(即直接映射的物理内存末端)所对应的线性地址存放在high_memory变量中,该变量被设为896MB。
896MB以上的页框不映射在第4个GB,所以内核不能直接访问。
所以,返回所分配页框线性地址的页分配器函数不适用于高端内存(即不适用于ZONE_HIGHMEM管理区内的页框)。
(两种方法:只能使用alloc_pages()和alloc_page();内核线性地址空间的最后128MB的高端内存映射区)
内核有3种机制将页框映射到高端内存:永久内核映射、临时内核映射、非连续内存分配
page_address_htable散列表
page_address_map
kmap()
kunmap()
enum km_type
kmap_atomic(struct page * page, enum km_type type)
kunmap_atomic()
外碎片external fragmentation
(页框管理,分配一组连续的页框)
buddy system(页框作为基本内存区)
每个管理区使用不同的buddy system。80x86中有3种:DMA、NORMAL、HIGHMEM。
每个buddy system使用的主要数据结构:mem_map数组、free_area数组。
即前边提到的struct free_area[] free_area;11个free_area类型元素的数组,每个元素对应一种块大小。
2. 内存区管理 memory area
内碎片internal fragmentation
(内存区管理,具有连续的物理地址和任意长度的内存单元序列)
分配小内存区如几十字节
slab分配器(同一页框中分配小内存区)
slab分配器模式最早用于SUN的Solaris 2.4 OS中。
高速缓存描述符kmem_cache_t
高速缓存分两种:
普通:只由slab allocator用于自己的目的
专用:由内核其余部分使用
系统初始化时:kmem_cache_init() && kmem_cache_sizes_init()建立普通高速缓存
kmem_cache_create()创建专用高速缓存
kmem_cache_destroy()
slab描述符
Interfacing the Slab Allocator with the Zoned Page Frame Allocator
void * kmem_getpages(kmem_cache_t *cachep, int flags)
void kmem_freepages(kmem_cache_t *cachep, void *addr)
给高速缓存分配、释放slab
cache_grow()
slab_destroy()
对象描述符kmem_bufctl_t
分配、释放slab的对象
kmem_cache_alloc()
kmem_cache_free()
通用对象
void * kmalloc(size_t size, int flags);
void kfree()
内存池memory pool,由mempool_t对象描述
3. 非连续内存区管理
内存区映射到连续的页框:能充分利用告诉缓存
通过连续的线性地址访问非连续的页框:优点能避免外碎片,缺点是必须打乱内核页表(适用于对内存区请求不太频繁的情况)
为活动的交换区分配数据结构、为模块分配空间、为某些I/O驱动程序分配缓冲区。
0xc0000000
非连续内存区线性地址空间:VMALLOC_START ---- VMALLOC_END
非连续内存区之间插入4KB的安全区。
每个非连续内存区对应着一个vm_struct描述符
其中,flags字段标示了映射的内存类型:
VM_ALLOC 使用vmalloc()得到的页
VM_MAP 使用vmp()映射的已经被分配的页
VM_IOREMAP 使用ioremap()映射的硬件设备的板上内存
get_vm_area()
分配、释放非连续内存区
void * vmalloc(unsigned long size);
void vfree();
本文来自ChinaUnix博客,如果查看原文请点:http://blog.chinaunix.net/u2/74638/showart_1108932.html |
|