kmallocとvmallocの違い


kmalloc/vmallocは、両者とも仮想アドレスを取得するものですが、以下のような違いを有しています。

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      8
vmallocはページ単位で取得され、そのページは、その取得毎にアロケートしています。

従って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;
}

補足

GFP_KERNEL/GFP_HIGHMEM等のページ取得時のフラグのGFPは、Get Free Pageの事だそうです。


最終更新 2012/04/22 19:31:20 - north
(2012/04/22 19:31:20 作成)


検索

アクセス数
3689359
最近のコメント
コアダンプファイル - sakaia
list_head構造体 - yocto_no_yomikata
勧告ロックと強制ロック - wataash
LKMからのファイル出力 - 重松 宏昌
kprobe - ななし
ksetの実装 - スーパーコピー
カーネルスレッドとは - ノース
カーネルスレッドとは - nbyst
asmlinkageってなに? - ノース
asmlinkageってなに? - よろしく
Adsense
広告情報が設定されていません。