Linux Kernel - Memory Management

MMU

高性能处理器一般会提供一个内存管理单元(MMU) ,该单元辅助操作系统进行内存管理,提供虚拟地址和物理地址的映射、内存访问权限保护和 Cache 缓存控制等硬件支持。操作系统内核借助 MMU,可以让用户感觉到好像程序可以使用非常大的内存空间,从而使得编程人员在写程序时不用考虑计算机中的物理内存的实际容量。

内核把物理页作为内存管理的基本单元,对于32位CPU通常一页为4KB。页的数据结构如下,用来描述物理内存,而不是其包含的数据,内核用该数据结构来追踪系统的所有页。

struct page {
    unsigned long flags; //保存 页 状态,如 在内存中被locked
    atomic_t _count;     //页的使用计数 -1 表示没有被使用
    atomic_t _mapcount;
    unsigned long private;
    struct address_space *mapping;
    pgoff_t index;
    struct list_head lru;
    void *virtual;    // 页的虚拟地址
};

由于硬件条件限制,内核不会将所有页一致性处理,有些页在内存中以物理地址存在,不能用在特定的任务,因此内核把页划分成不同的区域,实际上内存区域的使用和布局是架构独立的,有些架构 ZONE_DMA 为空。


内存分配

1. 以页大小分配
struct page * alloc_pages(gfp_t gfp_mask, unsigned int order)
 - 分配 2 的 order 级数个连续物理页
void * page_address(struct page *page)
 - 将物理页转化成逻辑地址
unsigned long __get_free_pages(gfp_t gfp_mask, unsigned int order)
 - 等同 alloc_pages + page_address

unsigned long page;
page = __get_free_pages(GFP_KERNEL, 3);
if (!page) {
    /* insufficient memory: you must handle this error! */
    return –ENOMEM;
}

2. 以字节大小分配
void * kmalloc(size_t size, gfp_t flags)
 - 和用户空间 malloc() 类似

struct dog *p;
p = kmalloc(sizeof(struct dog), GFP_KERNEL);
if (!p)
    /* handle error ... */

gfp_t  标志分为三类,action modifiers, zone modifiers, type. 比较常用的 GFP_KERNEL 和 ATOMIC。
GFP_KERNEL 其含义是在内核空间的进程中申请内存。kmalloc()的底层依赖_ _get_free_pages()实现,分配标志的前缀 GFP 正好是这个底层函数的缩写。使用 GFP_ KERNEL 标志申请内存时,若暂时不能满足,则进程会睡眠等待页,即会引起阻塞,因此不能在中断上下文或持有自旋锁的时候使用GFP_KERNE 申请内存。
GFP_ATOMIC 在中断处理函数、tasklet 和内核定时器等非进程上下文中不能阻塞时使用,申请内存时,若不存在空闲页,则不等待,直接返回。
                      

void * vmalloc(unsigned long size)
 - 分配连续的虚拟地址,分配的物理内存可能不连续,修补其页表并映射内存为逻辑地址空间的连续块。vmalloc()一般用在为只存在于软件中(没有对应的硬件意义)的较大的顺序缓冲区分配内存,vmalloc()远大于_ _get_free_pages()的开销,为了完成 vmalloc(),新的页表需要被建立。因此,只是调用 vmalloc()来分配少量的内存(如 1 页)是不妥的。vmalloc()不能用在原子上下文中,因为它的内部实现使用了标志为 GFP_KERNEL 的kmalloc()。

内存释放

char *buf;
char *buf1;

buf = kmalloc(BUF_SIZE, GFP_ATOMIC);
if (!buf)
    /* error allocating memory ! */
kfree(buf);


buf1 = vmalloc(16 * PAGE_SIZE); /* get 16 pages */
if (!buf1)
/* error! failed to allocate memory */
/*
* buf now points to at least a 16*PAGE_SIZE bytes
* of virtually contiguous block of memory
*/

vfree(buf1);

Slab Layer

涉及大量对象的重复生成、使用和释放问题,用合适的方法使得在对象前后两次被使用时分配在同一块内存或同一类内存空间
且保留了基本的数据结构,就可以大大提高效率。

                                

/*创建 slab 缓存*/
static kmem_cache_t *xxx_cachep;
xxx_cachep = kmem_cache_create("xxx", sizeof(struct xxx),
            0, SLAB_HWCACHE_ALIGN|SLAB_PANIC, NULL, NULL);
/*分配 slab 缓存*/
struct xxx *ctx;
ctx = kmem_cache_alloc(xxx_cachep, GFP_KERNEL);
...//使用 slab 缓存
/*释放 slab 缓存*/
kmem_cache_free(xxx_cachep, ctx);
kmem_cache_destroy(xxx_cachep);

猜你喜欢

转载自blog.csdn.net/wu472269100/article/details/104563342