在Linux内核中,malloc和kmalloc是用于内存分配的函数,但它们分别用于用户空间和内核空间,且实现机制不同。
1. malloc(用户空间内存分配)
malloc是C标准库中的函数,用于在用户空间分配内存。它通常通过brk或mmap系统调用来实现。
分配机制
brk系统调用:malloc通过调整堆的顶部(brk指针)来分配内存。堆是一个连续的内存区域,brk指针指向堆的顶部。当malloc需要分配内存时,它会调用brk系统调用来扩展堆的大小。mmap系统调用:对于较大的内存分配,malloc可能会使用mmap系统调用,将文件或匿名内存映射到进程的地址空间。mmap分配的内存不依赖于堆,且可以独立释放。
源码分析
malloc的实现通常在C标准库(如glibc)中,而不是内核源码中。以下是一个简化的malloc实现逻辑:
void* malloc(size_t size) {
if (size <= 0) return NULL;
// 使用brk或mmap分配内存
void* ptr = sbrk(size);
if (ptr == (void*)-1) {
// 如果brk失败,尝试使用mmap
ptr = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
if (ptr == MAP_FAILED) {
return NULL;
}
}
return ptr;
}
2. kmalloc(内核空间内存分配)
kmalloc是Linux内核中用于分配小块内存的函数。它使用内核的SLAB分配器或SLUB分配器来管理内存。
分配机制
- SLAB/SLUB分配器:
kmalloc依赖于SLAB或SLUB分配器来管理内核内存。SLAB分配器将内存划分为多个大小不同的缓存(cache),每个缓存用于分配特定大小的内存块。SLUB是SLAB的改进版本,提供了更好的性能和更简单的实现。 - 内存分配时机:当调用
kmalloc时,内核会从适当的缓存中分配一个内存块。如果缓存中没有可用的内存块,内核会从伙伴系统(Buddy System)中分配一个页面,并将其分割成适当大小的块。
源码分析
kmalloc的实现位于内核源码的slab.c或slub.c中。以下是一个简化的kmalloc实现逻辑:
void* kmalloc(size_t size, gfp_t flags) {
struct kmem_cache *cache;
void *object;
// 根据大小选择合适的缓存
cache = kmalloc_slab(size, flags);
if (unlikely(ZERO_OR_NULL_PTR(cache)))
return cache;
// 从缓存中分配对象
object = slab_alloc(cache, flags, _RET_IP_);
return object;
}
kmalloc_slab:根据请求的大小选择合适的SLAB缓存。slab_alloc:从选定的缓存中分配一个内存块。
3. 内存分配的真正时机
- 用户空间(
malloc):当malloc调用brk或mmap时,内核会更新进程的内存映射,并分配物理内存。物理内存的分配可能延迟到实际访问内存时(即“按需分页”机制)。 - 内核空间(
kmalloc):当kmalloc调用时,内核会立即从SLAB/SLUB缓存中分配内存。如果缓存中没有可用内存,内核会从伙伴系统中分配页面,并将其添加到缓存中。
4. 总结
malloc:用于用户空间,通过brk或mmap系统调用分配内存,物理内存的分配可能延迟到实际访问时。kmalloc:用于内核空间,通过SLAB/SLUB分配器分配内存,物理内存的分配是立即进行的。
两者都依赖于内核的内存管理机制,但malloc在用户空间运行,而kmalloc在内核空间运行。
1284

被折叠的 条评论
为什么被折叠?



