メモリ確保 (kmalloc, vmalloc)

メモリ確保とは

 本章のメモリ確保とは、mallocの様な関数を用いて、動的にメモリを確保する処理を示します。Linuxデバイスドライバでは、stdlib.hが使えない為、malloc自体は使えません。その代わりに、Linuxデバイスドライバで使用可能なメモリ確保関数として、kmallocやvmallocが用意されていますので、それぞれについて使い方と動作を説明します。

kmallocの使い方

 Linuxデバイスドライバで最も使用されるメモリ確保関数がkmallocです。kmallocは以下の通り定義されてます。

kernel/mediatek/4.4/include/linux/slab.h

/**
 * kmalloc - allocate memory
 * @size: how many bytes of memory are required.
 * @flags: the type of memory to allocate.
 *
 * kmalloc is the normal method of allocating memory
 * for objects smaller than page size in the kernel.
 *
 * The @flags argument may be one of:
 *
 * %GFP_USER - Allocate memory on behalf of user.  May sleep.
 *
 * %GFP_KERNEL - Allocate normal kernel ram.  May sleep.
 *
 * %GFP_ATOMIC - Allocation will not sleep.  May use emergency pools.
 *   For example, use this inside interrupt handlers.
 *
 * %GFP_HIGHUSER - Allocate pages from high memory.
 *
 * %GFP_NOIO - Do not do any I/O at all while trying to get memory.
 *
 * %GFP_NOFS - Do not make any fs calls while trying to get memory.
 *
 * %GFP_NOWAIT - Allocation will not sleep.
 *
 * %__GFP_THISNODE - Allocate node-local memory only.
 *
 * %GFP_DMA - Allocation suitable for DMA.
 *   Should only be used for kmalloc() caches. Otherwise, use a
 *   slab created with SLAB_DMA.
 *
 * Also it is possible to set different flags by OR'ing
 * in one or more of the following additional @flags:
 *
 * %__GFP_COLD - Request cache-cold pages instead of
 *   trying to return cache-warm pages.
 *
 * %__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_REPEAT - If allocation fails initially, try once more before failing.
 *
 * There are other flags available as well, but these are not intended
 * for general use, and so are not documented here. For a full list of
 * potential flags, always refer to linux/gfp.h.
 */
static __always_inline void *kmalloc(size_t size, gfp_t flags)

 kmallocは、指定されたサイズのカーネルメモリを割り当てます。この関数は、割り当てたメモリのポインタを返します。割り当てられたメモリは使用後にkfree関数で解放する必要があります。第2引数は上記コメントに沿ってタイプを指定する必要があります。特に理由なければGFP_KERNEL(Allocate normal kernel ram)が使われます。

 kmallocの派生関数であるkzallocが、近接照度センサドライバでは以下で使われています。

kernel/mediatek/4.4/drivers/misc/mediatek/sensors-1.0/alsps/alsps.c

struct alsps_context *obj = kzalloc(sizeof(*obj), GFP_KERNEL);

kzallocは、kmallocと同様のメモリ確保関数ですが、割り当てられたメモリはゼロで初期化されます。

vmallocの使い方

 比較的大きめのサイズを確保する際に使われるメモリ確保関数がvmallocになります。vmallocは以下の通り定義されてます。

kernel/mediatek/4.4/mm/vmalloc.c

/**
 *	vmalloc  -  allocate virtually contiguous memory
 *	@size:		allocation size
 *	Allocate enough pages to cover @size from the page level
 *	allocator and map them into contiguous kernel virtual space.
 *
 *	For tight control over page level allocator and protection flags
 *	use __vmalloc() instead.
 */
void *vmalloc(unsigned long size)

 vmallocは、指定されたサイズの仮想メモリを割り当てます。この関数は、割り当てたメモリのポインタを返します。割り当てられたメモリは使用後にvfree関数で解放する必要があります。仮想メモリの為、kmallocにあったtypeの指定はありません。

最後に

 Linuxは、4KB程度のページ毎にメモリを確保していて、vmallocはそこから直接割り当てします。その為、引数がごく少量のサイズでも4KB使ってしまいます。
 kmallocではページをさらに分割したスラブから使用します。これにより少量のメモリ確保では消費量を抑えることができます。正し、こちらを使っても最低数百バイト程度は使われてしまうので注意が必要です。

 vmallocは比較的大きめのサイズを確保することはできますが、仮想メモリ上では連続した領域を割り当てる必要があります。その為、メモリの断片化により、起動して時間が経過することで、確保に失敗する場合もあるので、注意が必要です。

Appendix. デバッグ関連

 vmallocの取得元のページの状態は、/proc/buddyinfoから確認が可能です。(以下はbugreportから抜粋)

------ BUDDYINFO (/proc/buddyinfo) ------
Node 0, zone      DMA   2163    787    253    317    104     56     51     25      9      2      0 

左端から4KBの空ページ数、右に行くごとに倍のサイズの空ページ数(右端であれば4MB)を示しています

 kmallocの取得元のスラブの状態は/proc/slabinfoから確認が可能です。ただし、CONFIG_SLUB_DEBUGを有効にする必要があり、有効にすると管理情報によりメモリの消費量が増えてしまいます。本サイトが対象としているデバイスでは無効になっております。(以下はbugreportから抜粋)

*** Error dumping /proc/slabinfo (SLAB INFO): No such file or directory

/proc/meminfoから、スラブの総量は分かるので、スラブに問題がありそうならば、CONFIG_SLUB_DEBUGを有効にして、確認してみるのが一つの手となります。

------ MEMORY INFO (/proc/meminfo) ------
MemTotal:        1834484 kB
MemFree:           94720 kB
MemAvailable:     644000 kB
Buffers:           12760 kB
Cached:           666376 kB
SwapCached:         2572 kB
Active:           804704 kB
Inactive:         522000 kB
Active(anon):     473212 kB
Inactive(anon):   182256 kB
Active(file):     331492 kB
Inactive(file):   339744 kB
Unevictable:        2424 kB
Mlocked:            2424 kB
SwapTotal:        524284 kB
SwapFree:         458236 kB
Dirty:              3268 kB
Writeback:           728 kB
AnonPages:        649120 kB
Mapped:           471180 kB
Shmem:              5460 kB
Slab:             120476 kB
SReclaimable:      44312 kB
SUnreclaim:        76164 kB
KernelStack:       34976 kB
PageTables:        43312 kB
NFS_Unstable:          0 kB
Bounce:                0 kB
WritebackTmp:          0 kB
CommitLimit:     1441524 kB
Committed_AS:   58307008 kB
VmallocTotal:   258867136 kB
VmallocUsed:           0 kB
VmallocChunk:          0 kB
CmaTotal:              0 kB
CmaFree:               0 kB

コメント

タイトルとURLをコピーしました