在Linux内核中,内存分配涉及多个层次和策略,以适应不同的需求和优化。以下是一些常见的内核内存分配函数及其用途:
- kmalloc()
- 分配指定大小的连续物理内存块。
- 适用于小块内存的分配,通常用于内核数据结构。
- 返回指向分配内存的指针,如果分配失败,则返回NULL。
- 分配的内存是物理上连续的,因此可以被DMA(直接内存访问)设备安全地访问。
- 内核会在需要时尝试从slab缓存中满足kmalloc请求,以提高性能。
- kzalloc()
- 与kmalloc类似,但会将分配的内存块初始化为零。
- 适用于需要初始化为零的数据结构。
- kmalloc_array()
- 专门用于分配固定大小的数组,与kmalloc类似,但提供了数组大小的参数。
- vmalloc()
- 分配一个大的虚拟连续但物理上可能不连续的内存区域。
- 适用于大型数据结构或需要虚拟连续内存的场景。
- 返回指向分配内存的指针,如果分配失败,则返回NULL。
- 分配的内存页会被映射到进程的虚拟地址空间,但不会预先物理分配,只有在首次访问时才会发生物理分配(延迟分配)。
- vzalloc()
- 与vmalloc类似,但会将分配的内存块初始化为零。
- alloc_page()
- 分配一个物理内存页。
- 适用于需要单个内存页的场景。
- free_page()
- 释放一个由alloc_page()分配的内存页。
- __get_free_page()
- 类似于alloc_page(),但返回一个指向该页的指针,如果分配失败,则返回NULL。
- __free_page()
- 类似于free_page(),但接受一个指向页的指针作为参数。
- Slab分配器
- 对于小块内存的频繁分配和释放,Linux内核使用slab分配器。
- Slab分配器为每个常见的数据结构类型维护一个或多个缓存(slab),以优化分配和释放的性能。
- 使用如
kmem_cache_alloc()
和kmem_cache_free()
这样的函数来从slab缓存中分配和释放内存。
内存分配失败的处理:
当内核内存分配请求无法满足时(例如,因为系统内存不足),内核通常会尝试通过一些手段来释放内存,如回收页框、触发OOM-killer(内存不足杀手)等。如果所有手段都无法释放足够的内存,系统可能会进入panic状态,导致系统崩溃。
注意:内核编程需要谨慎处理内存分配和释放,因为错误的内存管理可能导致系统不稳定或安全漏洞。务必确保在不再需要内存时正确释放它,并避免内存泄漏。同时,要考虑到并发访问和竞态条件的问题,可能需要对内存访问进行同步。