kmalloc VS vmalloc
这两个是高频考点,不管在面试过程中,还是在实际项目中,如果涉及到底层Linux内核的开发,都会遇到这个问题。
kmalloc
和malloc
都是Linux内核中的内存分配函数。
但是,二者有什么区别,哪些场景下使用kmalloc
,哪些场景下使用vmalloc
?
先看概念
kmalloc, what is it ?
定义
kmalloc()
函数的操作与用户空间的malloc()
函数非常相似,不同之处在于多了一个flags参数。kmalloc()
函数是获取内核内存的简单接口,以字节为单位分配内存。如果需要整页内存,之前讨论的接口可能是更好的选择。然而,对于大多数内核分配,kmalloc()
是首选的接口。
函数在<linux/slab.h>中声明如下:
void * kmalloc(size_t size, int flags)
该函数返回一个指向至少size字节长度的内存区域的指针。分配的内存区域是物理连续的。出错时,它返回NULL。内核分配总是成功的,除非可用内存不足。因此,在所有调用kmalloc()后,必须检查NULL并适当处理错误。
它可能会分配比请求的更多,尽管无法知道多少更多!因为内核分配器的核心是基于页面的,所以一些分配可能会四舍五入以适应可用内存。内核永远不会返回比请求的内存少。如果内核无法找到至少所需的内存量,分配失败,函数返回NULL。
我们来看一个例子。假设您需要为一个虚构的dog结构动态分配足够的空间:
struct dog *ptr;
ptr = kmalloc(sizeof(struct dog), GFP_KERNEL);
if (!ptr)
/* 处理错误... */
如果kmalloc()
调用成功,ptr现在指向一个至少为请求大小的内存块。GFP_KERNEL
标志指定了在尝试获取返回给kmalloc()
调用者的内存时内存分配器的行为。
注意事项
在实际使用过程中,使用kmalloc()
函数时要注意内存泄漏,如果分配了内存但没有正确释放,会导致内核内存的浪费。在内核中释放由kmalloc()
分配的内存,需要使用kfree()
函数。例如:
kfree(ptr);
释放内存后,建议将指针设置为NULL,以避免悬挂指针:
ptr = NULL;
这样可以确保在以后使用这个指针时,不会引用已经释放的内存。在内核编程中,内存管理非常重要,确保正确分配和释放内存对于系统稳定性至关重要。
先看看函数的原型和实现
/**
* kmalloc - allocate kernel memory
* @size: how many bytes of memory are required.
* @flags: describe the allocation context
*
* kmalloc is the normal method of allocating memory
* for objects smaller than page size in the kernel.
*
* The allocated object address is aligned to at least ARCH_KMALLOC_MINALIGN
* bytes. For @size of power of two bytes, the alignment is also guaranteed
* to be at least to the size.
*
* The @flags argument may be one of the GFP flags defined at
* include/linux/gfp.h and described at
* :ref:`Documentation/core-api/mm-api.rst <mm-api-gfp-flags>`
*
* The recommended usage of the @flags is described at
* :ref:`Documentation/core-api/memory-allocation.rst <memory_allocation>`
*
* Below is a brief outline of the most useful GFP flags
*
* %GFP_KERNEL
* Allocate normal kernel ram. May sleep.
*
* %GFP_NOWAIT
* Allocation will not sleep.
*
* %GFP_ATOMIC
* Allocation will not sleep. May use emergency pools.
*
* Also it is possible to set different flags by OR'ing
* in one or more of the following additional @flags:
*
* %__GFP_ZERO
* Zero the allocated memory before returning. Also see kzalloc().
*
* %__GFP_HIGH
* This allocation has high priority and may use emergency pools.
*
* %__GFP_NOFAIL
* Indicate that this allocation is in no way allowed to fail
* (think twice before using).
*
* %__GFP_NORETRY
* If memory is not immediately available,
* then give up at once.
*
* %__GFP_NOWARN
* If allocation fails, don't issue any warnings.
*
* %__GFP_RETRY_MAYFAIL
* Try really hard to succeed the allocation but fail
* eventually.
*/
#ifndef CONFIG_SLOB
static __always_inline __alloc_size(1) void *kmalloc(size_t size, gfp_t flags)
{
if (__builtin_constant_p(size) && size) {
unsigned int index;
if (size > KMALLOC_MAX_CACHE_SIZE)
return kmalloc_large(size, flags);
index = kmalloc_index(size);
return kmalloc_trace(
kmalloc_caches[kmalloc_type(flags)][index],
flags, size);
}
return __kmalloc(size, flags);
}
#else
static __always_inline __alloc_size(1) void *kmalloc(size_t size, gfp_t flags)
{
if (__builtin_constant_p(size) && size > KMALLOC_MAX_CACHE_SIZE)
return kmalloc_large(size, flags);
return __kmalloc(size, flags);
}
#endif
未完待续。。。