요약·해설과 원문, 전문 번역을 서로 분리했습니다. API 이름, symbol, source path는 원문 표기를 사용합니다.
1. 요약·해설
원문의 핵심 논리와 kernel programming 관점의 보충 설명입니다. 아래의 전문 번역과는 별도로 작성했습니다.
2. 영어 원문 전체
번역 기준이 된 Linux v6.18.37 원문입니다. 줄 번호는 이 버전의 파일 좌표입니다.
원문 전체 펼치기
Kernel Memory Leak Detector
===========================
Kmemleak provides a way of detecting possible kernel memory leaks in a
way similar to a `tracing garbage collector
<https://en.wikipedia.org/wiki/Tracing_garbage_collection>`_,
with the difference that the orphan objects are not freed but only
reported via /sys/kernel/debug/kmemleak. A similar method is used by the
Valgrind tool (``memcheck --leak-check``) to detect the memory leaks in
user-space applications.
Usage
-----
CONFIG_DEBUG_KMEMLEAK in "Kernel hacking" has to be enabled. A kernel
thread scans the memory every 10 minutes (by default) and prints the
number of new unreferenced objects found. If the ``debugfs`` isn't already
mounted, mount with::
# mount -t debugfs nodev /sys/kernel/debug/
To display the details of all the possible scanned memory leaks::
# cat /sys/kernel/debug/kmemleak
To trigger an intermediate memory scan::
# echo scan > /sys/kernel/debug/kmemleak
To clear the list of all current possible memory leaks::
# echo clear > /sys/kernel/debug/kmemleak
New leaks will then come up upon reading ``/sys/kernel/debug/kmemleak``
again.
Note that the orphan objects are listed in the order they were allocated
and one object at the beginning of the list may cause other subsequent
objects to be reported as orphan.
Memory scanning parameters can be modified at run-time by writing to the
``/sys/kernel/debug/kmemleak`` file. The following parameters are supported:
- off
disable kmemleak (irreversible)
- stack=on
enable the task stacks scanning (default)
- stack=off
disable the tasks stacks scanning
- scan=on
start the automatic memory scanning thread (default)
- scan=off
stop the automatic memory scanning thread
- scan=<secs>
set the automatic memory scanning period in seconds
(default 600, 0 to stop the automatic scanning)
- scan
trigger a memory scan
- clear
clear list of current memory leak suspects, done by
marking all current reported unreferenced objects grey,
or free all kmemleak objects if kmemleak has been disabled.
- dump=<addr>
dump information about the object found at <addr>
Kmemleak can also be disabled at boot-time by passing ``kmemleak=off`` on
the kernel command line.
Memory may be allocated or freed before kmemleak is initialised and
these actions are stored in an early log buffer. The size of this buffer
is configured via the CONFIG_DEBUG_KMEMLEAK_MEM_POOL_SIZE option.
If CONFIG_DEBUG_KMEMLEAK_DEFAULT_OFF are enabled, the kmemleak is
disabled by default. Passing ``kmemleak=on`` on the kernel command
line enables the function.
If you are getting errors like "Error while writing to stdout" or "write_loop:
Invalid argument", make sure kmemleak is properly enabled.
Basic Algorithm
---------------
The memory allocations via :c:func:`kmalloc`, :c:func:`vmalloc`,
:c:func:`kmem_cache_alloc` and
friends are traced and the pointers, together with additional
information like size and stack trace, are stored in a rbtree.
The corresponding freeing function calls are tracked and the pointers
removed from the kmemleak data structures.
An allocated block of memory is considered orphan if no pointer to its
start address or to any location inside the block can be found by
scanning the memory (including saved registers). This means that there
might be no way for the kernel to pass the address of the allocated
block to a freeing function and therefore the block is considered a
memory leak.
The scanning algorithm steps:
1. mark all objects as white (remaining white objects will later be
considered orphan)
2. scan the memory starting with the data section and stacks, checking
the values against the addresses stored in the rbtree. If
a pointer to a white object is found, the object is added to the
gray list
3. scan the gray objects for matching addresses (some white objects
can become gray and added at the end of the gray list) until the
gray set is finished
4. the remaining white objects are considered orphan and reported via
/sys/kernel/debug/kmemleak
Some allocated memory blocks have pointers stored in the kernel's
internal data structures and they cannot be detected as orphans. To
avoid this, kmemleak can also store the number of values pointing to an
address inside the block address range that need to be found so that the
block is not considered a leak. One example is __vmalloc().
Testing specific sections with kmemleak
---------------------------------------
Upon initial bootup your /sys/kernel/debug/kmemleak output page may be
quite extensive. This can also be the case if you have very buggy code
when doing development. To work around these situations you can use the
'clear' command to clear all reported unreferenced objects from the
/sys/kernel/debug/kmemleak output. By issuing a 'scan' after a 'clear'
you can find new unreferenced objects; this should help with testing
specific sections of code.
To test a critical section on demand with a clean kmemleak do::
# echo clear > /sys/kernel/debug/kmemleak
... test your kernel or modules ...
# echo scan > /sys/kernel/debug/kmemleak
Then as usual to get your report with::
# cat /sys/kernel/debug/kmemleak
Freeing kmemleak internal objects
---------------------------------
To allow access to previously found memory leaks after kmemleak has been
disabled by the user or due to an fatal error, internal kmemleak objects
won't be freed when kmemleak is disabled, and those objects may occupy
a large part of physical memory.
In this situation, you may reclaim memory with::
# echo clear > /sys/kernel/debug/kmemleak
Kmemleak API
------------
See the include/linux/kmemleak.h header for the functions prototype.
- ``kmemleak_init`` - initialize kmemleak
- ``kmemleak_alloc`` - notify of a memory block allocation
- ``kmemleak_alloc_percpu`` - notify of a percpu memory block allocation
- ``kmemleak_vmalloc`` - notify of a vmalloc() memory allocation
- ``kmemleak_free`` - notify of a memory block freeing
- ``kmemleak_free_part`` - notify of a partial memory block freeing
- ``kmemleak_free_percpu`` - notify of a percpu memory block freeing
- ``kmemleak_update_trace`` - update object allocation stack trace
- ``kmemleak_not_leak`` - mark an object as not a leak
- ``kmemleak_transient_leak`` - mark an object as a transient leak
- ``kmemleak_ignore`` - do not scan or report an object as leak
- ``kmemleak_scan_area`` - add scan areas inside a memory block
- ``kmemleak_no_scan`` - do not scan a memory block
- ``kmemleak_erase`` - erase an old value in a pointer variable
- ``kmemleak_alloc_recursive`` - as kmemleak_alloc but checks the recursiveness
- ``kmemleak_free_recursive`` - as kmemleak_free but checks the recursiveness
The following functions take a physical address as the object pointer
and only perform the corresponding action if the address has a lowmem
mapping:
- ``kmemleak_alloc_phys``
- ``kmemleak_free_part_phys``
- ``kmemleak_ignore_phys``
Dealing with false positives/negatives
--------------------------------------
The false negatives are real memory leaks (orphan objects) but not
reported by kmemleak because values found during the memory scanning
point to such objects. To reduce the number of false negatives, kmemleak
provides the kmemleak_ignore, kmemleak_scan_area, kmemleak_no_scan and
kmemleak_erase functions (see above). The task stacks also increase the
amount of false negatives and their scanning is not enabled by default.
The false positives are objects wrongly reported as being memory leaks
(orphan). For objects known not to be leaks, kmemleak provides the
kmemleak_not_leak function. The kmemleak_ignore could also be used if
the memory block is known not to contain other pointers and it will no
longer be scanned.
Some of the reported leaks are only transient, especially on SMP
systems, because of pointers temporarily stored in CPU registers or
stacks. Kmemleak defines MSECS_MIN_AGE (defaulting to 1000) representing
the minimum age of an object to be reported as a memory leak.
Limitations and Drawbacks
-------------------------
The main drawback is the reduced performance of memory allocation and
freeing. To avoid other penalties, the memory scanning is only performed
when the /sys/kernel/debug/kmemleak file is read. Anyway, this tool is
intended for debugging purposes where the performance might not be the
most important requirement.
To keep the algorithm simple, kmemleak scans for values pointing to any
address inside a block's address range. This may lead to an increased
number of false negatives. However, it is likely that a real memory leak
will eventually become visible.
Another source of false negatives is the data stored in non-pointer
values. In a future version, kmemleak could only scan the pointer
members in the allocated structures. This feature would solve many of
the false negative cases described above.
The tool can report false positives. These are cases where an allocated
block doesn't need to be freed (some cases in the init_call functions),
the pointer is calculated by other methods than the usual container_of
macro or the pointer is stored in a location not scanned by kmemleak.
Page allocations and ioremap are not tracked.
Testing with kmemleak-test
--------------------------
To check if you have all set up to use kmemleak, you can use the kmemleak-test
module, a module that deliberately leaks memory. Set CONFIG_SAMPLE_KMEMLEAK
as module (it can't be used as built-in) and boot the kernel with kmemleak
enabled. Load the module and perform a scan with::
# modprobe kmemleak-test
# echo scan > /sys/kernel/debug/kmemleak
Note that the you may not get results instantly or on the first scanning. When
kmemleak gets results, it'll log ``kmemleak: <count of leaks> new suspected
memory leaks``. Then read the file to see then::
# cat /sys/kernel/debug/kmemleak
unreferenced object 0xffff89862ca702e8 (size 32):
comm "modprobe", pid 2088, jiffies 4294680594 (age 375.486s)
hex dump (first 32 bytes):
6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b kkkkkkkkkkkkkkkk
6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b a5 kkkkkkkkkkkkkkk.
backtrace:
[<00000000e0a73ec7>] 0xffffffffc01d2036
[<000000000c5d2a46>] do_one_initcall+0x41/0x1df
[<0000000046db7e0a>] do_init_module+0x55/0x200
[<00000000542b9814>] load_module+0x203c/0x2480
[<00000000c2850256>] __do_sys_finit_module+0xba/0xe0
[<000000006564e7ef>] do_syscall_64+0x43/0x110
[<000000007c873fa6>] entry_SYSCALL_64_after_hwframe+0x44/0xa9
...
Removing the module with ``rmmod kmemleak_test`` should also trigger some
kmemleak results.
3. 한국어 전문 번역
영어 원문의 문단 순서와 의미를 유지한 전체 번역입니다. 코드, 함수명, symbol과 URL은 원문 표기를 유지합니다.
Kmemleak 개요와 사용법
1-79Kernel Memory Leak Detector
Kmemleak은 tracing garbage collector와 비슷한 방식으로 가능한 kernel memory leak을 탐지합니다. 차이점은 orphan object를 free하지 않고 `/sys/kernel/debug/kmemleak`을 통해 보고만 한다는 것입니다. userspace application의 memory leak을 찾는 Valgrind의 `memcheck --leak-check`도 비슷한 방식을 사용합니다.
사용법
`Kernel hacking`의 CONFIG_DEBUG_KMEMLEAK을 활성화해야 합니다. kernel thread는 기본적으로 10분마다 memory를 scan하고 새로 발견한 unreferenced object 수를 출력합니다. `debugfs`가 아직 mount되지 않았다면 다음과 같이 mount하십시오.
# mount -t debugfs nodev /sys/kernel/debug/
scan한 모든 possible memory leak의 상세 정보를 표시하려면 다음을 실행합니다.
# cat /sys/kernel/debug/kmemleak
중간 memory scan을 실행하려면 다음을 사용합니다.
# echo scan > /sys/kernel/debug/kmemleak
현재 possible memory leak 목록 전체를 지우려면 다음을 사용합니다.
# echo clear > /sys/kernel/debug/kmemleak
그다음 `/sys/kernel/debug/kmemleak`을 다시 읽으면 새로운 leak이 나타납니다.
orphan object는 allocation 순서로 나열되며 목록 앞쪽 object 하나가 뒤의 다른 object들을 orphan으로 보고하게 만들 수 있다는 점에 유의하십시오.
`/sys/kernel/debug/kmemleak` 파일에 써서 runtime에 memory scanning parameter를 바꿀 수 있습니다. 지원 parameter는 다음과 같습니다.
`off`: kmemleak을 비활성화하며 되돌릴 수 없습니다.
`stack=on`: task stack scanning을 활성화하며 기본값입니다.
`stack=off`: task stack scanning을 비활성화합니다.
`scan=on`: 자동 memory scanning thread를 시작하며 기본값입니다.
`scan=off`: 자동 memory scanning thread를 중지합니다.
`scan=<secs>`: 자동 scanning period를 second 단위로 설정합니다. 기본값은 600이며 0은 자동 scanning을 중지합니다.
`scan`: memory scan을 실행합니다.
`clear`: 현재 보고된 모든 unreferenced object를 grey로 표시해 현재 memory leak suspect 목록을 지웁니다. kmemleak이 비활성화된 경우에는 모든 kmemleak object를 free합니다.
`dump=<addr>`: `<addr>`에서 찾은 object 정보를 dump합니다.
kernel command line에 `kmemleak=off`를 전달해 boot 시점에 Kmemleak을 비활성화할 수도 있습니다.
kmemleak 초기화 전에 memory가 allocation 또는 free될 수 있으며 이 동작은 early log buffer에 저장됩니다. buffer 크기는 CONFIG_DEBUG_KMEMLEAK_MEM_POOL_SIZE option으로 구성합니다.
CONFIG_DEBUG_KMEMLEAK_DEFAULT_OFF가 활성화되어 있으면 kmemleak은 기본적으로 비활성화됩니다. kernel command line에 `kmemleak=on`을 전달하면 기능이 활성화됩니다.
`Error while writing to stdout` 또는 `write_loop: Invalid argument` 같은 error가 발생하면 kmemleak이 올바르게 활성화되어 있는지 확인하십시오.
white·grey object scanning algorithm
80-116기본 algorithm
`kmalloc`, `vmalloc`, `kmem_cache_alloc` 및 관련 함수의 memory allocation을 추적하고 pointer와 size, stack trace 같은 추가 정보를 rbtree에 저장합니다. 대응하는 free function call도 추적해 pointer를 kmemleak data structure에서 제거합니다.
memory를 scan할 때 저장된 register를 포함해 allocation block의 시작 address나 block 안의 어떤 위치를 가리키는 pointer도 찾을 수 없으면 그 block을 orphan으로 간주합니다. kernel이 allocation block address를 free function에 전달할 방법이 없을 수 있으므로 memory leak으로 보는 것입니다.
scanning algorithm 단계는 다음과 같습니다.
1. 모든 object를 white로 표시합니다. 끝까지 white인 object는 나중에 orphan으로 간주합니다.
2. data section과 stack에서 시작해 memory를 scan하고 값을 rbtree에 저장된 address와 비교합니다. white object를 가리키는 pointer를 찾으면 object를 grey list에 추가합니다.
3. 일치하는 address를 찾도록 grey object를 scan합니다. 일부 white object가 grey가 되어 grey list 끝에 추가될 수 있으며 grey set을 모두 처리할 때까지 반복합니다.
4. 남은 white object를 orphan으로 간주하고 `/sys/kernel/debug/kmemleak`을 통해 보고합니다.
일부 allocation block을 가리키는 pointer는 kernel internal data structure에 저장되어 orphan으로 탐지되지 않을 수 있습니다. 이를 피하기 위해 kmemleak은 block address range 안을 가리키는 value를 몇 개 찾아야 leak이 아닌 것으로 볼지도 저장할 수 있습니다. `__vmalloc()`이 한 예입니다.
특정 구간을 깨끗하게 재검사
117-137kmemleak으로 특정 구간 test
처음 boot했을 때 `/sys/kernel/debug/kmemleak` 출력이 매우 길 수 있습니다. 개발 중인 code에 bug가 많아도 그럴 수 있습니다. 이런 경우 `clear` command로 출력의 모든 unreferenced object report를 지울 수 있습니다. `clear` 뒤 `scan`을 실행하면 새로운 unreferenced object를 찾아 특정 code 구간을 test하는 데 도움이 됩니다.
깨끗한 kmemleak 상태에서 critical section을 필요할 때 test하려면 다음과 같이 합니다.
# echo clear > /sys/kernel/debug/kmemleak
... test your kernel or modules ...
# echo scan > /sys/kernel/debug/kmemleak
그런 다음 평소처럼 report를 얻습니다.
# cat /sys/kernel/debug/kmemleak
kmemleak internal object 회수
138-149kmemleak internal object free
사용자가 kmemleak을 비활성화했거나 fatal error로 비활성화된 뒤에도 앞서 찾은 memory leak에 접근할 수 있도록, kmemleak을 비활성화할 때 internal object를 free하지 않습니다. 이 object들이 physical memory의 큰 부분을 차지할 수 있습니다.
이 상황에서는 다음 명령으로 memory를 회수할 수 있습니다.
# echo clear > /sys/kernel/debug/kmemleak
Kmemleak API
150-179Kmemleak API
function prototype은 `include/linux/kmemleak.h` header를 참조하십시오.
`kmemleak_init`: kmemleak을 초기화합니다.
`kmemleak_alloc`: memory block allocation을 알립니다.
`kmemleak_alloc_percpu`: percpu memory block allocation을 알립니다.
`kmemleak_vmalloc`: `vmalloc()` memory allocation을 알립니다.
`kmemleak_free`: memory block free를 알립니다.
`kmemleak_free_part`: memory block의 일부 free를 알립니다.
`kmemleak_free_percpu`: percpu memory block free를 알립니다.
`kmemleak_update_trace`: object allocation stack trace를 갱신합니다.
`kmemleak_not_leak`: object를 leak이 아닌 것으로 표시합니다.
`kmemleak_transient_leak`: object를 transient leak으로 표시합니다.
`kmemleak_ignore`: object를 scan하거나 leak으로 보고하지 않습니다.
`kmemleak_scan_area`: memory block 안에 scan area를 추가합니다.
`kmemleak_no_scan`: memory block을 scan하지 않습니다.
`kmemleak_erase`: pointer variable의 이전 값을 지웁니다.
`kmemleak_alloc_recursive`: kmemleak_alloc과 같지만 recursion 여부를 검사합니다.
`kmemleak_free_recursive`: kmemleak_free와 같지만 recursion 여부를 검사합니다.
다음 함수는 physical address를 object pointer로 받고 address에 lowmem mapping이 있을 때만 해당 동작을 수행합니다.
`kmemleak_alloc_phys`
`kmemleak_free_part_phys`
`kmemleak_ignore_phys`
false positive와 false negative 처리
180-200false positive/negative 처리
false negative는 실제 memory leak, 즉 orphan object이지만 memory scan 중 발견한 값이 해당 object를 가리켜 kmemleak이 보고하지 않는 경우입니다. false negative를 줄이기 위해 `kmemleak_ignore`, `kmemleak_scan_area`, `kmemleak_no_scan`, `kmemleak_erase` 함수를 제공합니다. task stack도 false negative를 늘리며 기본적으로 scanning이 활성화되어 있지 않습니다.
false positive는 memory leak, 즉 orphan으로 잘못 보고된 object입니다. leak이 아닌 것으로 알려진 object에는 `kmemleak_not_leak`을 제공합니다. memory block에 다른 pointer가 없다고 알려져 있다면 `kmemleak_ignore`를 사용해 더 이상 scan하지 않을 수도 있습니다.
특히 SMP system에서는 pointer가 CPU register나 stack에 일시적으로 저장되어 report된 leak 일부가 transient일 수 있습니다. Kmemleak은 memory leak으로 보고할 object의 최소 age를 나타내는 MSECS_MIN_AGE를 정의하며 기본값은 1000입니다.
제한 사항과 단점
201-226제한 사항과 단점
가장 큰 단점은 memory allocation과 free 성능이 낮아지는 것입니다. 다른 비용을 피하기 위해 memory scanning은 `/sys/kernel/debug/kmemleak` 파일을 읽을 때만 수행합니다. 이 도구는 성능이 가장 중요한 요구 사항이 아닐 수 있는 debugging용입니다.
algorithm을 단순하게 유지하려고 block address range 안의 어떤 address든 가리키는 값을 scan합니다. 이 때문에 false negative가 늘어날 수 있지만 실제 memory leak은 결국 드러날 가능성이 높습니다.
non-pointer value에 저장된 data도 false negative의 원인입니다. 향후에는 allocation structure의 pointer member만 scan할 수 있으며 그러면 위에서 설명한 많은 false negative를 해결할 수 있습니다.
도구가 false positive를 보고할 수도 있습니다. allocation block을 free할 필요가 없는 경우, 일부 init_call function이 그 예입니다. pointer가 일반적인 `container_of` macro가 아닌 다른 방식으로 계산되거나 kmemleak이 scan하지 않는 위치에 저장된 경우도 있습니다.
page allocation과 ioremap은 추적하지 않습니다.
kmemleak-test module 검증
227-259kmemleak-test로 test
kmemleak 사용 설정이 모두 갖춰졌는지 확인하려면 의도적으로 memory를 leak하는 `kmemleak-test` module을 사용할 수 있습니다. CONFIG_SAMPLE_KMEMLEAK을 module로 설정하십시오. built-in으로는 사용할 수 없습니다. kmemleak을 활성화해 kernel을 boot하고 module을 load한 다음 scan을 실행합니다.
# modprobe kmemleak-test
# echo scan > /sys/kernel/debug/kmemleak
즉시 또는 첫 scan에서 결과가 나오지 않을 수 있습니다. kmemleak이 결과를 얻으면 `kmemleak: <count of leaks> new suspected memory leaks`를 log합니다. 그다음 파일을 읽으면 다음과 같은 결과를 볼 수 있습니다.
# cat /sys/kernel/debug/kmemleak
unreferenced object 0xffff89862ca702e8 (size 32):
comm "modprobe", pid 2088, jiffies 4294680594 (age 375.486s)
hex dump (first 32 bytes):
6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b kkkkkkkkkkkkkkkk
6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b a5 kkkkkkkkkkkkkkk.
backtrace:
[<00000000e0a73ec7>] 0xffffffffc01d2036
[<000000000c5d2a46>] do_one_initcall+0x41/0x1df
[<0000000046db7e0a>] do_init_module+0x55/0x200
[<00000000542b9814>] load_module+0x203c/0x2480
[<00000000c2850256>] __do_sys_finit_module+0xba/0xe0
[<000000006564e7ef>] do_syscall_64+0x43/0x110
[<000000007c873fa6>] entry_SYSCALL_64_after_hwframe+0x44/0xa9
...
unreferenced object report에서 leak 원인을 추적할 핵심 필드를 정리했습니다.
`rmmod kmemleak_test`로 module을 제거해도 일부 kmemleak 결과가 발생해야 합니다.
요약과 해설
kmemleak.rst:1-259Kmemleak은 allocation metadata를 rbtree에 기록하고 kernel memory에서 각 object를 가리키는 값을 tracing해 도달할 수 없는 white object를 leak suspect로 보고합니다. object를 자동으로 free하지 않으므로 report를 읽고 실제 생명주기와 비교해야 합니다.
pointer처럼 보이는 값, 임시 register·stack reference, scan하지 않는 영역 때문에 false negative나 false positive가 생길 수 있습니다. 특정 code 구간을 clear·scan 순서로 격리하고 API annotation과 최소 object age를 활용해 결과를 정제하는 것이 중요합니다.