요약·해설과 원문, 전문 번역을 서로 분리했습니다. API 이름, symbol, source path는 원문 표기를 사용합니다.
1. 요약·해설
원문의 핵심 논리와 kernel programming 관점의 보충 설명입니다. 아래의 전문 번역과는 별도로 작성했습니다.
2. 영어 원문 전체
번역 기준이 된 Linux v6.18.37 원문입니다. 줄 번호는 이 버전의 파일 좌표입니다.
원문 전체 펼치기
.. _memory_allocation:
=======================
Memory Allocation Guide
=======================
Linux provides a variety of APIs for memory allocation. You can
allocate small chunks using `kmalloc` or `kmem_cache_alloc` families,
large virtually contiguous areas using `vmalloc` and its derivatives,
or you can directly request pages from the page allocator with
`alloc_pages`. It is also possible to use more specialized allocators,
for instance `cma_alloc` or `zs_malloc`.
Most of the memory allocation APIs use GFP flags to express how that
memory should be allocated. The GFP acronym stands for "get free
pages", the underlying memory allocation function.
Diversity of the allocation APIs combined with the numerous GFP flags
makes the question "How should I allocate memory?" not that easy to
answer, although very likely you should use
::
kzalloc(<size>, GFP_KERNEL);
Of course there are cases when other allocation APIs and different GFP
flags must be used.
Get Free Page flags
===================
The GFP flags control the allocators behavior. They tell what memory
zones can be used, how hard the allocator should try to find free
memory, whether the memory can be accessed by the userspace etc. The
:ref:`Documentation/core-api/mm-api.rst <mm-api-gfp-flags>` provides
reference documentation for the GFP flags and their combinations and
here we briefly outline their recommended usage:
* Most of the time ``GFP_KERNEL`` is what you need. Memory for the
kernel data structures, DMAable memory, inode cache, all these and
many other allocations types can use ``GFP_KERNEL``. Note, that
using ``GFP_KERNEL`` implies ``GFP_RECLAIM``, which means that
direct reclaim may be triggered under memory pressure; the calling
context must be allowed to sleep.
* If the allocation is performed from an atomic context, e.g interrupt
handler, use ``GFP_NOWAIT``. This flag prevents direct reclaim and
IO or filesystem operations. Consequently, under memory pressure
``GFP_NOWAIT`` allocation is likely to fail. Users of this flag need
to provide a suitable fallback to cope with such failures where
appropriate.
* If you think that accessing memory reserves is justified and the kernel
will be stressed unless allocation succeeds, you may use ``GFP_ATOMIC``.
* Untrusted allocations triggered from userspace should be a subject
of kmem accounting and must have ``__GFP_ACCOUNT`` bit set. There
is the handy ``GFP_KERNEL_ACCOUNT`` shortcut for ``GFP_KERNEL``
allocations that should be accounted.
* Userspace allocations should use either of the ``GFP_USER``,
``GFP_HIGHUSER`` or ``GFP_HIGHUSER_MOVABLE`` flags. The longer
the flag name the less restrictive it is.
``GFP_HIGHUSER_MOVABLE`` does not require that allocated memory
will be directly accessible by the kernel and implies that the
data is movable.
``GFP_HIGHUSER`` means that the allocated memory is not movable,
but it is not required to be directly accessible by the kernel. An
example may be a hardware allocation that maps data directly into
userspace but has no addressing limitations.
``GFP_USER`` means that the allocated memory is not movable and it
must be directly accessible by the kernel.
You may notice that quite a few allocations in the existing code
specify ``GFP_NOIO`` or ``GFP_NOFS``. Historically, they were used to
prevent recursion deadlocks caused by direct memory reclaim calling
back into the FS or IO paths and blocking on already held
resources. Since 4.12 the preferred way to address this issue is to
use new scope APIs described in
:ref:`Documentation/core-api/gfp_mask-from-fs-io.rst <gfp_mask_from_fs_io>`.
Other legacy GFP flags are ``GFP_DMA`` and ``GFP_DMA32``. They are
used to ensure that the allocated memory is accessible by hardware
with limited addressing capabilities. So unless you are writing a
driver for a device with such restrictions, avoid using these flags.
And even with hardware with restrictions it is preferable to use
`dma_alloc*` APIs.
GFP flags and reclaim behavior
------------------------------
Memory allocations may trigger direct or background reclaim and it is
useful to understand how hard the page allocator will try to satisfy that
or another request.
* ``GFP_KERNEL & ~__GFP_RECLAIM`` - optimistic allocation without _any_
attempt to free memory at all. The most light weight mode which even
doesn't kick the background reclaim. Should be used carefully because it
might deplete the memory and the next user might hit the more aggressive
reclaim.
* ``GFP_KERNEL & ~__GFP_DIRECT_RECLAIM`` (or ``GFP_NOWAIT``)- optimistic
allocation without any attempt to free memory from the current
context but can wake kswapd to reclaim memory if the zone is below
the low watermark. Can be used from either atomic contexts or when
the request is a performance optimization and there is another
fallback for a slow path.
* ``(GFP_KERNEL|__GFP_HIGH) & ~__GFP_DIRECT_RECLAIM`` (aka ``GFP_ATOMIC``) -
non sleeping allocation with an expensive fallback so it can access
some portion of memory reserves. Usually used from interrupt/bottom-half
context with an expensive slow path fallback.
* ``GFP_KERNEL`` - both background and direct reclaim are allowed and the
**default** page allocator behavior is used. That means that not costly
allocation requests are basically no-fail but there is no guarantee of
that behavior so failures have to be checked properly by callers
(e.g. OOM killer victim is allowed to fail currently).
* ``GFP_KERNEL | __GFP_NORETRY`` - overrides the default allocator behavior
and all allocation requests fail early rather than cause disruptive
reclaim (one round of reclaim in this implementation). The OOM killer
is not invoked.
* ``GFP_KERNEL | __GFP_RETRY_MAYFAIL`` - overrides the default allocator
behavior and all allocation requests try really hard. The request
will fail if the reclaim cannot make any progress. The OOM killer
won't be triggered.
* ``GFP_KERNEL | __GFP_NOFAIL`` - overrides the default allocator behavior
and all allocation requests will loop endlessly until they succeed.
This might be really dangerous especially for larger orders.
Selecting memory allocator
==========================
The most straightforward way to allocate memory is to use a function
from the kmalloc() family. And, to be on the safe side it's best to use
routines that set memory to zero, like kzalloc(). If you need to
allocate memory for an array, there are kmalloc_array() and kcalloc()
helpers. The helpers struct_size(), array_size() and array3_size() can
be used to safely calculate object sizes without overflowing.
The maximal size of a chunk that can be allocated with `kmalloc` is
limited. The actual limit depends on the hardware and the kernel
configuration, but it is a good practice to use `kmalloc` for objects
smaller than page size.
The address of a chunk allocated with `kmalloc` is aligned to at least
ARCH_KMALLOC_MINALIGN bytes. For sizes which are a power of two, the
alignment is also guaranteed to be at least the respective size. For other
sizes, the alignment is guaranteed to be at least the largest power-of-two
divisor of the size.
Chunks allocated with kmalloc() can be resized with krealloc(). Similarly
to kmalloc_array(): a helper for resizing arrays is provided in the form of
krealloc_array().
For large allocations you can use vmalloc() and vzalloc(), or directly
request pages from the page allocator. The memory allocated by `vmalloc`
and related functions is not physically contiguous.
If you are not sure whether the allocation size is too large for
`kmalloc`, it is possible to use kvmalloc() and its derivatives. It will
try to allocate memory with `kmalloc` and if the allocation fails it
will be retried with `vmalloc`. There are restrictions on which GFP
flags can be used with `kvmalloc`; please see kvmalloc_node() reference
documentation. Note that `kvmalloc` may return memory that is not
physically contiguous.
If you need to allocate many identical objects you can use the slab
cache allocator. The cache should be set up with kmem_cache_create() or
kmem_cache_create_usercopy() before it can be used. The second function
should be used if a part of the cache might be copied to the userspace.
After the cache is created kmem_cache_alloc() and its convenience
wrappers can allocate memory from that cache.
When the allocated memory is no longer needed it must be freed.
Objects allocated by `kmalloc` can be freed by `kfree` or `kvfree`. Objects
allocated by `kmem_cache_alloc` can be freed with `kmem_cache_free`, `kfree`
or `kvfree`, where the latter two might be more convenient thanks to not
needing the kmem_cache pointer.
The same rules apply to _bulk and _rcu flavors of freeing functions.
Memory allocated by `vmalloc` can be freed with `vfree` or `kvfree`.
Memory allocated by `kvmalloc` can be freed with `kvfree`.
Caches created by `kmem_cache_create` should be freed with
`kmem_cache_destroy` only after freeing all the allocated objects first.
3. 한국어 전문 번역
영어 원문의 문단 순서와 의미를 유지한 전체 번역입니다. 코드, 함수명, symbol과 URL은 원문 표기를 유지합니다.
Memory allocation guide 개요
1-28Memory allocation anchor는 `memory_allocation`입니다.
Memory Allocation Guide
Linux는 다양한 memory allocation API를 제공합니다. 작은 chunk는 `kmalloc` 또는 `kmem_cache_alloc` 계열로, 큰 virtually contiguous area는 `vmalloc`과 그 파생 API로 할당할 수 있습니다. `alloc_pages`로 page allocator에 page를 직접 요청할 수도 있고, `cma_alloc`이나 `zs_malloc` 같은 전문 allocator를 사용할 수도 있습니다.
대부분의 memory allocation API는 memory를 어떻게 할당할지 표현하기 위해 GFP flag를 사용합니다. GFP는 기반 memory allocation function인 'get free pages'를 뜻합니다.
Allocation API가 다양하고 GFP flag도 많으므로 'memory를 어떻게 할당해야 하는가?'라는 질문에 답하기가 쉽지는 않습니다. 그래도 대부분의 경우 다음 호출을 사용하게 됩니다.
kzalloc(<size>, GFP_KERNEL);
물론 다른 allocation API와 다른 GFP flag를 사용해야 하는 경우도 있습니다.
Get Free Page flag 선택
29-87Get Free Page flags
GFP flag는 allocator의 동작을 제어합니다. 사용할 수 있는 memory zone, allocator가 free memory를 찾기 위해 어느 정도까지 시도할지, userspace에서 memory에 접근할 수 있는지 등을 지정합니다. `Documentation/core-api/mm-api.rst`의 `mm-api-gfp-flags`에는 GFP flag와 조합의 reference가 있으며, 여기서는 권장 용도를 간단히 정리합니다.
- 대부분은 `GFP_KERNEL`이 적합합니다. Kernel data structure, DMA 가능한 memory, inode cache를 비롯한 많은 allocation에 사용할 수 있습니다. `GFP_KERNEL`은 `GFP_RECLAIM`을 포함하므로 memory pressure에서 direct reclaim이 일어날 수 있고 caller context는 sleep할 수 있어야 합니다.
- Interrupt handler 같은 atomic context에서 allocation한다면 `GFP_NOWAIT`를 사용합니다. Direct reclaim과 IO 또는 filesystem operation을 막으므로 memory pressure에서는 실패할 가능성이 높습니다. 적절한 경우 caller는 실패에 대응할 fallback을 제공해야 합니다.
- Memory reserve 접근이 정당하고 allocation 실패 시 kernel이 심한 압박을 받는다면 `GFP_ATOMIC`을 사용할 수 있습니다.
- Userspace에서 유발된 신뢰할 수 없는 allocation은 kmem accounting 대상이어야 하며 `__GFP_ACCOUNT` bit를 설정해야 합니다. Accounting이 필요한 `GFP_KERNEL` allocation에는 `GFP_KERNEL_ACCOUNT` shortcut이 있습니다.
- Userspace allocation에는 `GFP_USER`, `GFP_HIGHUSER`, `GFP_HIGHUSER_MOVABLE` 중 하나를 사용합니다. 이름이 길수록 제약이 적습니다. `GFP_HIGHUSER_MOVABLE`은 kernel이 직접 접근할 필요가 없고 data가 movable임을 뜻합니다. `GFP_HIGHUSER`는 movable하지 않지만 kernel이 직접 접근할 필요는 없습니다. Addressing 제한 없이 data를 userspace에 직접 map하는 hardware allocation이 예입니다. `GFP_USER`는 movable하지 않고 kernel이 직접 접근할 수 있어야 합니다.
기존 code에는 `GFP_NOIO` 또는 `GFP_NOFS`를 지정한 allocation이 적지 않습니다. 과거에는 direct memory reclaim이 FS 또는 IO path로 재진입한 뒤 이미 보유한 resource에서 block되어 생기는 recursion deadlock을 막기 위해 사용했습니다. Linux 4.12부터는 `Documentation/core-api/gfp_mask-from-fs-io.rst`의 `gfp_mask_from_fs_io`에 설명한 새 scope API가 권장됩니다.
다른 legacy GFP flag로는 `GFP_DMA`와 `GFP_DMA32`가 있습니다. Addressing capability가 제한된 hardware에서도 할당 memory에 접근할 수 있게 하는 flag입니다. 그런 제약이 있는 device driver를 작성하는 경우가 아니라면 사용하지 마십시오. Hardware에 제약이 있더라도 `dma_alloc*` API를 사용하는 편이 좋습니다.
GFP flag와 reclaim 동작
88-131GFP flags and reclaim behavior
Memory allocation은 direct reclaim이나 background reclaim을 일으킬 수 있으므로 page allocator가 request를 충족하기 위해 어느 정도까지 시도하는지 이해하는 것이 유용합니다.
- `GFP_KERNEL & ~__GFP_RECLAIM`은 memory를 해제하려는 시도를 전혀 하지 않는 optimistic allocation입니다. Background reclaim도 깨우지 않는 가장 가벼운 mode입니다. Memory를 고갈시켜 다음 사용자가 더 공격적인 reclaim을 겪게 할 수 있으므로 주의해서 사용해야 합니다.
- `GFP_KERNEL & ~__GFP_DIRECT_RECLAIM`, 즉 `GFP_NOWAIT`는 현재 context에서 memory를 해제하려 하지 않는 optimistic allocation이지만 zone이 low watermark 아래라면 kswapd를 깨워 reclaim할 수 있습니다. Atomic context에서 사용하거나, request가 성능 최적화이고 별도의 slow-path fallback이 있을 때 사용할 수 있습니다.
- `(GFP_KERNEL|__GFP_HIGH) & ~__GFP_DIRECT_RECLAIM`, 즉 `GFP_ATOMIC`은 sleep하지 않는 allocation이며 비용이 큰 fallback을 통해 memory reserve 일부에 접근할 수 있습니다. 보통 interrupt 또는 bottom-half context에서 비용이 큰 slow-path fallback과 함께 사용합니다.
- `GFP_KERNEL`은 background reclaim과 direct reclaim을 모두 허용하며 기본 page allocator 동작을 사용합니다. Costly하지 않은 allocation request는 사실상 실패하지 않지만 이를 보장하지는 않으므로 caller는 실패를 올바르게 검사해야 합니다. 현재 OOM killer victim은 실패할 수 있습니다.
- `GFP_KERNEL | __GFP_NORETRY`는 기본 allocator 동작을 덮어쓰고 disruptive reclaim을 일으키는 대신 모든 allocation request를 일찍 실패시킵니다. 현재 구현에서는 reclaim을 한 번 수행하며 OOM killer는 호출하지 않습니다.
- `GFP_KERNEL | __GFP_RETRY_MAYFAIL`은 기본 동작을 덮어쓰고 모든 allocation request가 매우 적극적으로 시도하게 합니다. Reclaim이 진전하지 못하면 request가 실패하며 OOM killer는 실행하지 않습니다.
- `GFP_KERNEL | __GFP_NOFAIL`은 기본 동작을 덮어쓰고 모든 allocation request가 성공할 때까지 끝없이 반복하게 합니다. 특히 높은 order에서는 매우 위험할 수 있습니다.
Allocator 선택과 작은 object
132-155Memory allocator 선택 (Selecting memory allocator)
가장 간단한 memory allocation 방법은 `kmalloc()` 계열 function을 사용하는 것입니다. 안전을 위해 `kzalloc()`처럼 memory를 0으로 설정하는 routine을 사용하는 편이 좋습니다. Array memory에는 `kmalloc_array()`와 `kcalloc()` helper가 있습니다. `struct_size()`, `array_size()`, `array3_size()` helper를 사용하면 overflow 없이 object size를 안전하게 계산할 수 있습니다.
`kmalloc`으로 할당할 수 있는 chunk의 최대 크기는 제한됩니다. 실제 한계는 hardware와 kernel configuration에 따라 다르지만 page size보다 작은 object에 `kmalloc`을 사용하는 것이 좋습니다.
`kmalloc`이 할당한 chunk의 address는 최소 `ARCH_KMALLOC_MINALIGN` byte에 맞춰 정렬됩니다. 크기가 2의 거듭제곱이면 적어도 해당 크기만큼 정렬되는 것도 보장합니다. 그 밖의 크기에서는 그 크기를 나누는 가장 큰 2의 거듭제곱만큼 정렬됩니다.
`kmalloc()`으로 할당한 chunk는 `krealloc()`으로 크기를 바꿀 수 있습니다. `kmalloc_array()`에 대응하는 array resize helper로 `krealloc_array()`가 제공됩니다.
큰 allocation과 slab cache
156-175큰 allocation에는 `vmalloc()`과 `vzalloc()`을 사용하거나 page allocator에 page를 직접 요청할 수 있습니다. `vmalloc`과 관련 function이 할당한 memory는 physically contiguous하지 않습니다.
Allocation size가 `kmalloc`에 너무 큰지 확신할 수 없다면 `kvmalloc()`과 파생 API를 사용할 수 있습니다. 먼저 `kmalloc`으로 시도하고 실패하면 `vmalloc`로 다시 시도합니다. `kvmalloc`에 사용할 수 있는 GFP flag에는 제약이 있으므로 `kvmalloc_node()` reference를 확인해야 합니다. `kvmalloc`이 반환한 memory는 physically contiguous하지 않을 수 있습니다.
동일한 object를 많이 할당해야 한다면 slab cache allocator를 사용할 수 있습니다. 사용 전에 `kmem_cache_create()` 또는 `kmem_cache_create_usercopy()`로 cache를 설정해야 합니다. Cache 일부를 userspace로 복사할 수 있다면 두 번째 function을 사용합니다. Cache를 만든 뒤 `kmem_cache_alloc()`과 convenience wrapper로 해당 cache에서 memory를 할당합니다.
할당 memory 해제
176-188할당한 memory가 더 이상 필요하지 않으면 반드시 해제해야 합니다.
`kmalloc`이 할당한 object는 `kfree` 또는 `kvfree`로 해제합니다. `kmem_cache_alloc`이 할당한 object는 `kmem_cache_free`, `kfree`, `kvfree`로 해제할 수 있습니다. 뒤의 두 function은 `kmem_cache` pointer가 필요하지 않아 더 편리할 수 있습니다.
동일한 규칙은 freeing function의 `_bulk`와 `_rcu` variant에도 적용됩니다.
`vmalloc`이 할당한 memory는 `vfree` 또는 `kvfree`로 해제하고, `kvmalloc`이 할당한 memory는 `kvfree`로 해제합니다. `kmem_cache_create`로 만든 cache는 할당한 모든 object를 먼저 해제한 뒤 `kmem_cache_destroy`로 해제해야 합니다.
요약과 해설
memory-allocation.rst:1-188일반적인 sleep 가능 kernel context의 작은 allocation은 `kzalloc(size, GFP_KERNEL)`이 출발점입니다. Atomic context는 실패 가능성을 감수하고 `GFP_NOWAIT`를 사용하며 reserve 접근이 정당한 제한적 상황에서만 `GFP_ATOMIC`을 고려합니다.
작은 object는 `kmalloc` 계열, 큰 virtually contiguous area는 `vmalloc`, 크기 경계가 불확실하면 `kvmalloc`, 동일한 object를 반복 할당하면 slab cache를 사용합니다. `kvmalloc`과 `vmalloc` 결과는 physically contiguous하지 않을 수 있습니다.
Allocator와 해제 API를 맞추는 것이 중요합니다. `kvfree`는 kmalloc, vmalloc, kvmalloc 계열을 폭넓게 처리하며 slab cache는 모든 object를 먼저 해제한 뒤 `kmem_cache_destroy()`로 파괴합니다.