kmallocとvmallocの違い
kmalloc/vmallocは、両者とも仮想アドレスを取得するものですが、以下のような違いを有しています。
kmalocはオブジェクト単位(スラブ)で取得されます。このキャッシュは、kmaloc用として、8,16,32・・・4096,8192サイズで作成されており、引数で指定されるサイズの対応するスラブが取得されます。
従ってvmallocはクリティカルパスで使用できません。なおkmalocもそのキャッシュが無くなると、新規キャッシュのためページを取得することになり、kmalocの引数に、GFP_KERNEL/GFP_ATOMICを指定することで、クリティカルパスでの利用を可能としています。
kmalocはオブジェクト単位(スラブ)で取得されます。このキャッシュは、kmaloc用として、8,16,32・・・4096,8192サイズで作成されており、引数で指定されるサイズの対応するスラブが取得されます。
[ root@localhost kitamura]# cat /proc/slabinfo | grep kmalloc dma-kmalloc-4096 0 0 4096 dma-kmalloc-2048 0 0 2048 : dma-kmalloc-32 0 0 32 dma-kmalloc-16 0 0 16 dma-kmalloc-8 0 0 8 kmalloc-8192 36 36 8192 kmalloc-4096 114 128 4096 : kmalloc-64 3411 4032 64 kmalloc-32 7123 7808 32 kmalloc-16 6400 6400 16 kmalloc-8 8192 8192 8vmallocはページ単位で取得され、そのページは、その取得毎にアロケートしています。
従ってvmallocはクリティカルパスで使用できません。なおkmalocもそのキャッシュが無くなると、新規キャッシュのためページを取得することになり、kmalocの引数に、GFP_KERNEL/GFP_ATOMICを指定することで、クリティカルパスでの利用を可能としています。
void *__kmalloc(size_t size, gfp_t flags)
{
return __do_kmalloc(size, flags, __builtin_return_address(0));
}
static __always_inline void *__do_kmalloc(size_t size, gfp_t flags,
void *caller)
{
struct kmem_cache *cachep;
void *ret;
サイズに合うスラブのキャッシュを取得
cachep = __find_general_cachep(size, flags);
if (unlikely(ZERO_OR_NULL_PTR(cachep)))
return cachep;
取得できなければ、キャッシュを取得して割り当てる
ret = __cache_alloc(cachep, flags, caller);
trace_kmalloc((unsigned long) caller, ret,
size, cachep->buffer_size, flags);
return ret;
}
void *vmalloc(unsigned long size)
{
最終的にGFP_KERNEL | __GFP_HIGHMEMで__vmalloc_node_rangeがコールされます。
return __vmalloc_node_flags(size, -1, GFP_KERNEL | __GFP_HIGHMEM);
}
void *__vmalloc_node_range(unsigned long size, unsigned long align,
unsigned long start, unsigned long end, gfp_t gfp_mask,
pgprot_t prot, int node, void *caller)
{
struct vm_struct *area;
void *addr;
unsigned long real_size = size;
サイズをページアライメントに修正します。
size = PAGE_ALIGN(size);
if (!size || (size >> PAGE_SHIFT) > totalram_pages)
goto fail;
サイズを満たすリニアアドレス空間を取得します。
area = __get_vm_area_node(size, align, VM_ALLOC | VM_UNLIST,
start, end, node, gfp_mask, caller);
if (!area)
goto fail;
上記リ割り当てたリニアアドレスに対応するページを割り当て、ページテーブルを設定します。
addr = __vmalloc_area_node(area, gfp_mask, prot, node, caller);
if (!addr)
return NULL;
vmlistをヘッダーとするリストにvmmallocで割り当てたareaをリストします。
insert_vmalloc_vmlist(area);
kmemleak_objectにこのメモリオブジェクトをリストします。
CONFIG_DEBUG_KMEMLEAKでない時、未処理です。
kmemleak_alloc(addr, real_size, 3, gfp_mask);
return addr;
fail:
warn_alloc_failed(gfp_mask, 0,
"vmalloc: allocation failure: %lu bytes\n",
real_size);
return NULL;
}






