kernel/memory_management/heap.html · kernel/memory_management/heap.rst 공식 원문 ↗

Zephyr 3.7.0 · Kernel · Memory Management

메모리 힙

동기화 방식과 memory 배치 조건에 맞춰 단일·다중 heap을 선택하고 allocation 수명주기와 event를 관리합니다.

Official pathkernel/memory_management/heap.html
Source filekernel/memory_management/heap.rst
Source versionZephyr 3.7.0
TranslationFull · reviewed

본문 기준: Zephyr 3.7.0 LTS3 · 이후 유지보수 패치는 별도입니다.

Part 1

요약·해설

Thread가 기다릴 수 있는 k_heap, 호출자가 locking하는 constant-time sys_heap, 비연속 backend를 선택하는 sys_multi_heap, 공용 system heap의 책임 경계를 함께 설명합니다.

k_heap

timeout · sync

sys_heap

caller locking

multi heap

backend choice

Part 2

접을 수 있는 영어 원문 전체

영어 원문 전체 펼치기
원문 SHA-256 C8AC0540800839C8761524A498B70F34C263202F1234BE670184FC345CB4C643
.. _heap_v2:

Memory Heaps
############

Zephyr provides a collection of utilities that allow threads to
dynamically allocate memory.

Synchronized Heap Allocator
***************************

Creating a Heap
===============

The simplest way to define a heap is statically, with the
:c:macro:`K_HEAP_DEFINE` macro.  This creates a static :c:struct:`k_heap` variable
with a given name that manages a memory region of the
specified size.

Heaps can also be created to manage arbitrary regions of
application-controlled memory using :c:func:`k_heap_init`.

Allocating Memory
=================

Memory can be allocated from a heap using :c:func:`k_heap_alloc`,
passing it the address of the heap object and the number of bytes
desired.  This functions similarly to standard C ``malloc()``,
returning a NULL pointer on an allocation failure.

The heap supports blocking operation, allowing threads to go to sleep
until memory is available.  The final argument is a
:c:type:`k_timeout_t` timeout value indicating how long the thread may
sleep before returning, or else one of the constant timeout values
:c:macro:`K_NO_WAIT` or :c:macro:`K_FOREVER`.

Releasing Memory
================

Memory allocated with :c:func:`k_heap_alloc` must be released using
:c:func:`k_heap_free`.  Similar to standard C ``free()``, the pointer
provided must be either a ``NULL`` value or a pointer previously
returned by :c:func:`k_heap_alloc` for the same heap.  Freeing a
``NULL`` value is defined to have no effect.

Low Level Heap Allocator
************************

The underlying implementation of the :c:struct:`k_heap`
abstraction is provided a data structure named :c:struct:`sys_heap`.  This
implements exactly the same allocation semantics, but
provides no kernel synchronization tools.  It is available for
applications that want to manage their own blocks of memory in
contexts (for example, userspace) where synchronization is unavailable
or more complicated.  Unlike ``k_heap``, all calls to any ``sys_heap``
functions on a single heap must be serialized by the caller.
Simultaneous use from separate threads is disallowed.

Implementation
==============

Internally, the ``sys_heap`` memory block is partitioned into "chunks"
of 8 bytes.  All allocations are made out of a contiguous region of
chunks.  The first chunk of every allocation or unused block is
prefixed by a chunk header that stores the length of the chunk, the
length of the next lower ("left") chunk in physical memory, a bit
indicating whether the chunk is in use, and chunk-indexed link
pointers to the previous and next chunk in a "free list" to which
unused chunks are added.

The heap code takes reasonable care to avoid fragmentation.  Free
block lists are stored in "buckets" by their size, each bucket storing
blocks within one power of two (i.e. a bucket for blocks of 3-4
chunks, another for 5-8, 9-16, etc...) this allows new allocations to
be made from the smallest/most-fragmented blocks available.  Also, as
allocations are freed and added to the heap, they are automatically
combined with adjacent free blocks to prevent fragmentation.

All metadata is stored at the beginning of the contiguous block of
heap memory, including the variable-length list of bucket list heads
(which depend on heap size).  The only external memory required is the
:c:struct:`sys_heap` structure itself.

The ``sys_heap`` functions are unsynchronized.  Care must be taken by
any users to prevent concurrent access.  Only one context may be
inside one of the API functions at a time.

The heap code takes care to present high performance and reliable
latency.  All ``sys_heap`` API functions are guaranteed to complete
within constant time.  On typical architectures, they will all
complete within 1-200 cycles.  One complexity is that the search of
the minimum bucket size for an allocation (the set of free blocks that
"might fit") has a compile-time upper bound of iterations to prevent
unbounded list searches, at the expense of some fragmentation
resistance.  This :kconfig:option:`CONFIG_SYS_HEAP_ALLOC_LOOPS` value may be
chosen by the user at build time, and defaults to a value of 3.

Multi-Heap Wrapper Utility
**************************

The ``sys_heap`` utility requires that all managed memory be in a
single contiguous block.  It is common for complicated microcontroller
applications to have more complicated memory setups that they still
want to manage dynamically as a "heap".  For example, the memory might
exist as separate discontiguous regions, different areas may have
different cache, performance or power behavior, peripheral devices may
only be able to perform DMA to certain regions, etc...

For those situations, Zephyr provides a ``sys_multi_heap`` utility.
Effectively this is a simple wrapper around a set of one or more
``sys_heap`` objects.  It should be initialized after its child heaps
via :c:func:`sys_multi_heap_init`, after which each heap can be added
to the managed set via :c:func:`sys_multi_heap_add_heap`.  No
destruction utility is provided; just as for ``sys_heap``,
applications that want to destroy a multi heap should simply ensure
all allocated blocks are freed (or at least will never be used again)
and repurpose the underlying memory for another usage.

It has a single pair of allocation entry points,
:c:func:`sys_multi_heap_alloc` and
:c:func:`sys_multi_heap_aligned_alloc`.  These behave identically to
the ``sys_heap`` functions with similar names, except that they also
accept an opaque "configuration" parameter.  This pointer is
uninspected by the multi heap code itself; instead it is passed to a
callback function provided at initialization time.  This
application-provided callback is responsible for doing the underlying
allocation from one of the managed heaps, and may use the
configuration parameter in any way it likes to make that decision.

When unused, a multi heap may be freed via
:c:func:`sys_multi_heap_free`.  The application does not need to pass
a configuration parameter.  Memory allocated from any of the managed
``sys_heap`` objects may be freed with in the same way.

System Heap
***********

The :dfn:`system heap` is a predefined memory allocator that allows
threads to dynamically allocate memory from a common memory region in
a :c:func:`malloc`-like manner.

Only a single system heap is defined. Unlike other heaps or memory
pools, the system heap cannot be directly referenced using its
memory address.

The size of the system heap is configurable to arbitrary sizes,
subject to space availability.

A thread can dynamically allocate a chunk of heap memory by calling
:c:func:`k_malloc`. The address of the allocated chunk is
guaranteed to be aligned on a multiple of pointer sizes. If a suitable
chunk of heap memory cannot be found ``NULL`` is returned.

When the thread is finished with a chunk of heap memory it can release
the chunk back to the system heap by calling :c:func:`k_free`.

Defining the Heap Memory Pool
=============================

The size of the heap memory pool is specified using the
:kconfig:option:`CONFIG_HEAP_MEM_POOL_SIZE` configuration option.

By default, the heap memory pool size is zero bytes. This value instructs
the kernel not to define the heap memory pool object. The maximum size is limited
by the amount of available memory in the system. The project build will fail in
the link stage if the size specified can not be supported.

In addition, each subsystem (board, driver, library, etc) can set a custom
requirement by defining a Kconfig option with the prefix
``HEAP_MEM_POOL_ADD_SIZE_`` (this value is in bytes). If multiple subsystems
specify custom values, the sum of these will be used as the minimum requirement.
If the application tries to set a value that's less than the minimum value, this
will be ignored and the minimum value will be used instead.

To force a smaller than minimum value to be used, the application may enable the
:kconfig:option:`CONFIG_HEAP_MEM_POOL_IGNORE_MIN` option. This can be useful
when optimizing the heap size and the minimum requirement can be more accurately
determined for a specific application.

Allocating Memory
=================

A chunk of heap memory is allocated by calling :c:func:`k_malloc`.

The following code allocates a 200 byte chunk of heap memory, then fills it
with zeros. A warning is issued if a suitable chunk is not obtained.

.. code-block:: c

    char *mem_ptr;

    mem_ptr = k_malloc(200);
    if (mem_ptr != NULL)) {
        memset(mem_ptr, 0, 200);
	...
    } else {
        printf("Memory not allocated");
    }

Releasing Memory
================

A chunk of heap memory is released by calling :c:func:`k_free`.

The following code allocates a 75 byte chunk of memory, then releases it
once it is no longer needed.

.. code-block:: c

    char *mem_ptr;

    mem_ptr = k_malloc(75);
    ... /* use memory block */
    k_free(mem_ptr);

Suggested Uses
==============

Use the heap memory pool to dynamically allocate memory in a
:c:func:`malloc`-like manner.

Configuration Options
=====================

Related configuration options:

* :kconfig:option:`CONFIG_HEAP_MEM_POOL_SIZE`

API Reference
=============

.. doxygengroup:: heap_apis

.. doxygengroup:: low_level_heap_allocator

.. doxygengroup:: multi_heap_wrapper

Heap listener
*************

.. doxygengroup:: heap_listener_apis

Part 3

한국어 전문 번역

Zephyr는 thread가 실행 중에 필요한 크기만큼 memory를 동적으로 할당하고 반환할 수 있도록 여러 heap utility를 제공합니다. 선택지는 kernel synchronization과 timeout을 제공하는 k_heap, 호출자가 locking을 책임지는 sys_heap, 여러 비연속 영역을 한 interface로 묶는 sys_multi_heap, 공용 system heap입니다.

동기화 힙 할당자

힙 만들기

가장 간단한 정적 정의 방법은 K_HEAP_DEFINE macro입니다. 지정 이름의 정적 struct k_heap variable과 지정 크기 memory 영역을 함께 만들고 그 영역을 관리합니다.

Application이 소유한 임의 memory 영역을 관리하려면 k_heap_init()으로 heap을 만들 수도 있습니다.

메모리 할당

k_heap_alloc()에 heap object 주소와 원하는 byte 수를 넘겨 memory를 할당합니다. 표준 C malloc()과 비슷하며 실패하면 NULL을 반환합니다.

이 heap은 blocking operation을 지원하므로 memory가 생길 때까지 thread를 sleep시킬 수 있습니다. 마지막 인수 k_timeout_t는 얼마나 기다릴지 나타내며 K_NO_WAIT 또는 K_FOREVER도 사용할 수 있습니다.

메모리 반환

k_heap_alloc()으로 얻은 memory는 k_heap_free()로 반환해야 합니다. 표준 C free()처럼 pointer는 NULL이거나 같은 heap의 k_heap_alloc()이 전에 반환한 값이어야 합니다. NULL 해제는 아무 효과가 없습니다.

저수준 힙 할당자

struct k_heap의 내부 구현은 struct sys_heap이라는 data structure가 제공합니다. Allocation 의미는 같지만 kernel synchronization 도구가 없습니다. Userspace처럼 synchronization을 사용할 수 없거나 더 복잡한 context에서 application이 memory block을 직접 관리할 때 쓸 수 있습니다. 같은 sys_heap의 모든 함수 호출은 호출자가 직렬화해야 하며 여러 thread가 동시에 사용하면 안 됩니다.

구현

sys_heap memory block은 내부적으로 8-byte chunk로 나뉘며 allocation 하나는 연속 chunk 영역을 차지합니다. 각 allocation 또는 free block의 첫 chunk 앞에는 header가 붙습니다. Header는 현재 chunk 길이, physical memory에서 바로 왼쪽에 있는 chunk 길이, 사용 중 여부 bit, 그리고 free list에서 이전·다음 block을 가리키는 chunk-indexed link pointer를 저장합니다.

Fragmentation을 줄이기 위해 free block list를 크기별 bucket으로 나눕니다. 각 bucket은 한 power-of-two 범위, 예를 들어 3~4, 5~8, 9~16 chunk를 담습니다. 새 allocation은 들어맞을 수 있는 가장 작고 잘게 나뉜 block부터 사용합니다. Block을 free할 때 인접 free block과 자동 병합해 연속 공간을 회복합니다.

가변 길이 bucket-head 목록을 포함한 모든 metadata는 연속 heap memory block 시작 부분에 저장됩니다. Bucket 수는 heap 크기에 따라 달라지고, 외부에서 필요한 memory는 struct sys_heap object뿐입니다.

sys_heap 함수에는 synchronization이 없습니다. 한 순간에는 context 하나만 같은 heap API 안에 있어야 하므로 사용자가 concurrent access를 막아야 합니다.

Heap code는 높은 성능과 예측 가능한 latency를 목표로 하며 모든 sys_heap API는 constant time 안에 끝납니다. 일반 architecture에서 약 1~200 cycle입니다. Allocation에 맞을 가능성이 있는 최소 bucket을 검색할 때 unbounded list search를 막기 위해 compile-time 최대 반복 수를 둡니다. 이 제한은 fragmentation 저항성과 맞바꾸는 값이며 CONFIG_SYS_HEAP_ALLOC_LOOPS로 정하고 기본값은 3입니다.

멀티 힙 래퍼 유틸리티

sys_heap은 관리 memory가 하나의 연속 block에 있어야 합니다. 복잡한 microcontroller application에는 비연속 영역, 서로 다른 cache·성능·전력 특성, 특정 영역에만 DMA할 수 있는 peripheral처럼 여러 memory 조건이 흔합니다.

이런 경우 sys_multi_heap이 하나 이상의 sys_heap object를 감싸는 단순 wrapper를 제공합니다. Child heap을 먼저 초기화한 뒤 sys_multi_heap_init()으로 wrapper를 만들고 sys_multi_heap_add_heap()으로 각 heap을 등록합니다. 별도 destruction utility는 없습니다. 파괴하려면 모든 allocation을 해제했거나 다시는 쓰지 않을 것을 보장한 뒤 underlying memory를 다른 용도로 전환합니다.

Allocation entry point는 sys_multi_heap_alloc()과 sys_multi_heap_aligned_alloc()입니다. 비슷한 이름의 sys_heap 함수와 같지만 opaque configuration pointer를 더 받습니다. Multi-heap code는 값을 해석하지 않고 초기화 때 등록한 application callback으로 전달합니다. Callback이 configuration을 해석해 관리 heap 중 하나를 골라 실제 allocation을 수행합니다.

사용이 끝난 multi-heap allocation은 sys_multi_heap_free()로 반환하며 configuration을 다시 전달할 필요가 없습니다. 관리되는 어느 sys_heap에서 할당한 memory라도 같은 방식으로 해제할 수 있습니다.

시스템 힙

System heap은 공통 memory 영역에서 malloc()과 비슷하게 동적 memory를 제공하는 미리 정의된 allocator입니다. System 전체에 하나만 존재하고 다른 heap이나 memory pool과 달리 memory 주소로 직접 참조할 수 없습니다.

크기는 사용 가능한 공간 범위 안에서 임의 값으로 설정합니다. Thread는 k_malloc()으로 block을 할당합니다. 주소는 pointer 크기의 배수로 정렬되고 적합한 block이 없으면 NULL입니다. 사용 후에는 k_free()로 system heap에 돌려줍니다.

힙 메모리 풀 정의

CONFIG_HEAP_MEM_POOL_SIZE가 heap memory pool 크기를 정합니다. 기본값 0 byte는 kernel이 pool object를 만들지 말라는 뜻입니다. 최대치는 system의 실제 가용 memory이며 지원할 수 없는 크기를 지정하면 link 단계에서 build가 실패합니다.

Board, driver, library 같은 subsystem은 HEAP_MEM_POOL_ADD_SIZE_ prefix의 Kconfig option으로 byte 단위 추가 요구량을 선언할 수 있습니다. 여러 subsystem의 값은 합산되어 최소 요구량이 됩니다. Application이 그보다 작은 값을 지정하면 무시되고 최소값이 사용됩니다.

정확한 application 분석을 바탕으로 최소값보다 작은 heap을 강제하려면 CONFIG_HEAP_MEM_POOL_IGNORE_MIN을 활성화할 수 있습니다.

메모리 할당

다음 원문 예제는 k_malloc()으로 200 byte를 할당해 0으로 채우고, 얻지 못하면 경고를 출력합니다. 원문에는 if 조건의 닫는 괄호가 하나 더 있으며 이를 수정하지 않고 그대로 보존합니다.

char *mem_ptr;

mem_ptr = k_malloc(200);
if (mem_ptr != NULL)) {
    memset(mem_ptr, 0, 200);
    ...
} else {
    printf("Memory not allocated");
}

메모리 반환

다음 예제는 75 byte를 할당하고 더는 필요하지 않을 때 k_free()합니다.

char *mem_ptr;

mem_ptr = k_malloc(75);
... /* use memory block */
k_free(mem_ptr);

권장 용도

malloc()과 비슷한 방식으로 runtime memory가 필요할 때 heap memory pool을 사용합니다.

설정 옵션

관련 configuration option은 CONFIG_HEAP_MEM_POOL_SIZE입니다.

API 참고

동기화 힙 API: heap_apis

K_HEAP_DEFINE(name, bytes)

요청한 크기의 정적 memory 영역과 동기화된 k_heap을 정의하고 초기화합니다. Kernel 시작 뒤에는 k_heap_init()을 호출한 것처럼 &name을 사용할 수 있습니다. Metadata를 담기 위한 최소 영역 크기를 강제하므로 아주 작은 heap은 필요한 만큼 padding됩니다.

매개변수

  • name: struct k_heap object의 symbol 이름
  • bytes: memory 영역 크기(byte)
K_HEAP_DEFINE_NOCACHE(name, bytes)

요청한 크기의 정적 memory 영역과 k_heap을 uncached memory에 정의하고 초기화합니다. Kernel 시작 뒤 &name을 바로 사용할 수 있고, metadata 최소 크기보다 작은 요청은 padding됩니다.

매개변수

  • name: struct k_heap object의 symbol 이름
  • bytes: memory 영역 크기(byte)
void k_heap_init(struct k_heap *h, void *mem, size_t bytes)

사용자가 지정한 memory 영역 위에 동기화된 k_heap object를 구성합니다. 임의 alignment와 크기를 전달할 수 있지만 내부 sys_heap의 alignment 제한 때문에 모든 byte를 할당 가능한 data로 쓰지는 못할 수 있습니다.

매개변수

  • h: 초기화할 heap 구조체
  • mem: 사용하지 않은 memory pointer
  • bytes: memory 영역 크기(byte)
void *k_heap_aligned_alloc(struct k_heap *h, size_t align, size_t bytes, k_timeout_t timeout)

k_heap_alloc()과 같지만 반환 주소가 byte 단위 power-of-two align의 배수가 되도록 할당합니다. 반환 memory는 k_heap_free()로 돌려줍니다. ISR에서 호출할 때 timeout은 반드시 K_NO_WAIT여야 하며 CONFIG_MULTITHREADING=n이면 모든 timeout을 K_NO_WAIT로 취급합니다.

매개변수

  • h: 할당할 heap
  • align: power-of-two alignment(byte)
  • bytes: 요청 byte 수
  • timeout: 대기 시간 또는 K_NO_WAIT

반환값: 호출자가 사용할 수 있는 memory pointer이며 실패하면 NULL입니다.

void *k_heap_alloc(struct k_heap *h, size_t bytes, k_timeout_t timeout)

Heap 소유 영역에서 buffer를 할당합니다. 즉시 공간이 없으면 timeout 동안 memory가 반환되기를 기다리고, 만료 전에도 할당하지 못하면 NULL을 반환합니다. 할당 memory는 pointer 크기의 배수로 정렬됩니다. ISR에서는 K_NO_WAIT만 허용되고 CONFIG_MULTITHREADING=n이면 timeout 종류와 관계없이 기다리지 않습니다.

매개변수

  • h: 할당할 heap
  • bytes: 원하는 block 크기
  • timeout: 대기 시간, K_NO_WAIT 또는 K_FOREVER

반환값: 유효한 heap memory pointer 또는 NULL입니다.

void *k_heap_realloc(struct k_heap *h, void *ptr, size_t bytes, k_timeout_t timeout)

기존 k_heap allocation의 크기를 바꿉니다. 즉시 새 공간을 확보하지 못하면 timeout 동안 기다리고, 만료되면 NULL을 반환합니다. 재할당 memory는 pointer 크기의 배수로 정렬됩니다. ISR에서는 K_NO_WAIT만 허용되며 CONFIG_MULTITHREADING=n이면 모든 timeout은 K_NO_WAIT입니다.

매개변수

  • h: 대상 heap
  • ptr: 이전 allocation이 반환한 원래 pointer
  • bytes: 새 block 크기
  • timeout: 대기 시간 또는 K_NO_WAIT

반환값: 사용할 memory pointer 또는 NULL입니다.

void k_heap_free(struct k_heap *h, void *mem)

k_heap_alloc()이 반환한 block을 같은 heap에 돌려 다른 호출자가 재사용하게 합니다. NULL을 전달하는 것은 유효하며 아무 동작도 하지 않습니다.

매개변수

  • h: memory를 반환할 heap
  • mem: 유효한 memory block 또는 NULL
void *k_aligned_alloc(size_t align, size_t size)

System heap에서 지정 alignment로 memory를 할당합니다. C11 aligned_alloc()과 유사하지만 size가 align의 정수배일 필요 없이 0이 아닌 어떤 크기도 받을 수 있다는 차이가 있습니다.

매개변수

  • align: 요청 alignment(byte)
  • size: 요청 memory 크기(byte)

반환값: 성공하면 할당 주소, 실패하면 NULL입니다.

void *k_malloc(size_t size)

전통적인 malloc() 의미로 system heap memory pool에서 memory를 할당합니다. 반환 memory는 pointer 크기의 배수로 정렬됩니다.

매개변수

  • size: 요청 memory 크기(byte)

반환값: 성공하면 할당 주소, 실패하면 NULL입니다.

void k_free(void *ptr)

전통적인 free() 의미로 system heap에서 할당한 memory를 반환합니다. ptr이 NULL이면 아무 동작도 하지 않습니다.

매개변수

  • ptr: 이전에 할당한 memory pointer
void *k_calloc(size_t nmemb, size_t size)

전통적인 calloc() 의미로 배열 memory를 system heap에서 할당하고 0으로 채웁니다.

매개변수

  • nmemb: 배열 element 수
  • size: 각 element 크기(byte)

반환값: 성공하면 할당 주소, 실패하면 NULL입니다.

void *k_realloc(void *ptr, size_t size)

기존 system-heap allocation의 크기를 바꾸면서 내용을 보존합니다. 제자리 확장이 가능하면 같은 pointer를 반환하고, 아니면 새 block으로 data를 복사한 뒤 이전 block을 해제합니다. 줄이는 경우 제자리에서 잘라 남은 memory를 heap에 돌려줍니다. 새 block 할당이 실패하면 NULL을 반환하되 원래 block은 해제하거나 수정하지 않습니다.

매개변수

  • ptr: 이전 allocation의 원래 pointer
  • size: 새 요청 크기(byte)

반환값: 사용할 memory pointer 또는 NULL입니다.

struct k_heap

동기화된 Zephyr kernel heap object입니다. 선언은 에 있습니다.

저수준 할당자 API: low_level_heap_allocator

sys_heap_realloc(heap, ptr, bytes)

기본 pointer alignment로 sys_heap_aligned_realloc()을 호출하는 저수준 heap 재할당 macro입니다.

void sys_heap_init(struct sys_heap *heap, void *mem, size_t bytes)

지정 memory를 관리하도록 sys_heap 구조체를 초기화합니다.

매개변수

  • heap: 초기화할 heap
  • mem: 사용하지 않은 memory를 가리키는 untyped pointer
  • bytes: mem 영역 크기
void *sys_heap_alloc(struct sys_heap *heap, size_t bytes)

사용하지 않은 block을 할당합니다. sys_heap_free() 전에는 다른 용도로 쓰지 않으며 공간이 없으면 NULL입니다. 시작 주소는 sizeof(void *)의 배수이고 더 큰 alignment가 필요하면 sys_heap_aligned_alloc()을 사용합니다. 내부 동기화가 없으므로 같은 heap에 대한 모든 호출을 사용자가 직렬화해야 합니다.

매개변수

  • heap: 할당할 heap
  • bytes: 요청 byte 수

반환값: 사용할 memory pointer 또는 NULL입니다.

void *sys_heap_aligned_alloc(struct sys_heap *heap, size_t align, size_t bytes)

sys_heap_alloc()과 같지만 반환 주소가 지정 power-of-two alignment의 배수가 됩니다. align=0이면 sys_heap_alloc()과 정확히 같고 반환 memory는 sys_heap_free()로 해제합니다.

매개변수

  • heap: 할당할 heap
  • align: power-of-two alignment(byte)
  • bytes: 요청 byte 수

반환값: 사용할 memory pointer 또는 NULL입니다.

void sys_heap_free(struct sys_heap *heap, void *mem)

sys_heap_alloc()이 반환한 memory를 해제해 재사용할 수 있게 합니다. 함수 진입 뒤 호출자는 해당 영역을 다시 사용하면 안 됩니다. 이 함수도 내부 동기화가 없으므로 locking은 호출자 책임입니다.

매개변수

  • heap: memory를 반환할 heap
  • mem: sys_heap_alloc()이 반환한 pointer
void *sys_heap_aligned_realloc(struct sys_heap *heap, void *ptr, size_t align, size_t bytes)

기존 allocation을 지정 alignment와 새 크기로 바꿉니다. 제자리 확장 가능 시 같은 pointer를 반환하고, 아니면 내용을 새 block으로 복사해 이전 block을 해제합니다. 축소는 제자리에서 잘라 남은 memory를 반환합니다. 새 allocation이 실패하면 원래 block을 유지한 채 NULL을 반환합니다.

매개변수

  • heap: 대상 heap
  • ptr: 기존 allocation pointer
  • align: power-of-two alignment
  • bytes: 새 block byte 수

반환값: 새 memory pointer 또는 NULL입니다.

size_t sys_heap_usable_size(struct sys_heap *heap, void *mem)

성공한 sys_heap_alloc() 또는 aligned allocation이 반환한 block의 실제 관리 크기를 byte로 돌려줍니다. Allocation granularity 때문에 요청보다 클 수 있으며 같은 pointer를 sys_heap_free()하기 전까지 heap code가 이 영역을 건드리지 않습니다.

매개변수

  • heap: block을 포함한 heap
  • mem: 이 heap에서 할당한 pointer

반환값: 실제 memory 영역 크기(byte)입니다.

bool sys_heap_validate(struct sys_heap *heap)

sys_heap 내부 무결성을 검사합니다. Unit test와 validation code용이지만 복잡한 runtime reliability 요구에도 쓸 수 있습니다. 모든 오류를 찾지는 못하지만 true이면 heap이 일관된 상태로 allocation과 기존 live pointer 해제를 처리할 수 있습니다.

매개변수

  • heap: 검사할 heap

반환값: 유효하면 true, 아니면 false입니다.

void sys_heap_stress(void *(*alloc_fn)(void *arg, size_t bytes), void (*free_fn)(void *arg, void *p), void *arg, size_t total_bytes, uint32_t op_count, void *scratch_mem, size_t scratch_bytes, int target_percent, struct z_heap_stress_result *result)

Heap allocation 검증용 stress-test rig입니다. op_count 동안 무작위 power-law 크기의 allocation/free를 골라 heap이 target_percent에 가깝게 차도록 유지합니다. Callback 방식이므로 원칙적으로 어떤 heap도 시험할 수 있고 성공·실패 allocation 수와 free 수를 result에 기록합니다.

매개변수

  • alloc_fn: allocation callback; context로 arg를 받음
  • free_fn: 할당 pointer를 해제하는 callback; context로 arg를 받음
  • arg: callback context
  • total_bytes: heap 초기화 byte 배열 크기
  • op_count: 시험 반복 횟수
  • scratch_mem: 시험 scratch memory; fragmentation 시험은 heap 절반 정도 권장
  • scratch_bytes: scratch memory 크기
  • target_percent: 무작위 선택이 맞출 1~100% fill; 높을수록 실패와 fragmentation이 많음
  • result: 시험 결과를 쓸 구조체
void sys_heap_print_info(struct sys_heap *heap, bool dump_chunks)

Heap 크기, chunk bucket, chunk list와 통계를 console에 출력해 내부 구조를 debug합니다.

매개변수

  • heap: 정보를 출력할 heap
  • dump_chunks: true이면 전체 chunk list도 출력

멀티 힙 API: multi_heap_wrapper

typedef void *(*sys_multi_heap_fn_t)(struct sys_multi_heap *mheap, void *cfg, size_t align, size_t size)

Opaque cfg 값으로 특정 sys_heap backend를 선택하고 호출자 대신 실제 allocation을 수행하는 application callback type입니다. 등록된 어느 backend든 고를 수 있고, 필요하면 요청 값을 padding하거나 aligned allocation을 사용할 수 있습니다. NULL을 반환하면 전체 allocation도 실패합니다.

매개변수

  • mheap: multi-heap 구조체
  • cfg: application이 자유롭게 해석하는 opaque 값
  • align: 요청 alignment 또는 무정렬을 뜻하는 0
  • size: 사용자가 요청한 byte 수

반환값: 할당 memory pointer 또는 NULL입니다.

void sys_multi_heap_init(struct sys_multi_heap *heap, sys_multi_heap_fn_t choice_fn)

Choice callback으로 sys_multi_heap을 초기화합니다. 각 child heap은 나중에 sys_multi_heap_add_heap()으로 등록해야 경계를 추적할 수 있습니다. Multi-heap은 보통 linker boundary나 devicetree memory 정의 같은 system configuration에서 SoC/board platform device가 boot 때 반정적으로 구성하며 application이 임의 조립하는 방식은 일반적이지 않습니다.

매개변수

  • heap: 초기화할 sys_multi_heap
  • choice_fn: allocation 때 backend를 고를 callback
void sys_multi_heap_add_heap(struct sys_multi_heap *mheap, struct sys_heap *heap, void *user_data)

기존 multi-heap에 sys_heap backend를 추가합니다. 내부가 heap 경계를 기록해 해제 pointer가 어느 backend에서 왔는지 판별할 수 있게 합니다.

매개변수

  • mheap: 추가 대상 multi-heap
  • heap: 추가할 sys_heap
  • user_data: 해당 heap에 연결할 임의 data pointer
void *sys_multi_heap_alloc(struct sys_multi_heap *mheap, void *cfg, size_t bytes)

지정 byte 수의 block을 multi-heap에서 할당합니다. Opaque cfg를 choice function에 넘겨 integration code가 backend를 선택하게 합니다.

매개변수

  • mheap: multi-heap pointer
  • cfg: sys_multi_heap_fn_t에 전달할 opaque configuration
  • bytes: 요청 byte 수

반환값: 유효한 heap memory pointer 또는 공간이 없으면 NULL입니다.

void *sys_multi_heap_aligned_alloc(struct sys_multi_heap *mheap, void *cfg, size_t align, size_t bytes)

sys_multi_heap_alloc()과 같되 반환 pointer의 power-of-two alignment를 추가로 지정합니다.

매개변수

  • mheap: multi-heap pointer
  • cfg: opaque configuration
  • align: power-of-two alignment(byte)
  • bytes: 요청 byte 수

반환값: 유효한 heap memory pointer 또는 NULL입니다.

const struct sys_multi_heap_rec *sys_multi_heap_get_heap(const struct sys_multi_heap *mheap, void *addr)

주어진 allocation 주소를 관리하는 특정 system heap과 user_data record를 찾습니다.

매개변수

  • mheap: multi-heap pointer
  • addr: sys_multi_heap_alloc()이 할당한 block 주소

반환값: 찾은 sys_multi_heap_rec pointer이며 해당 heap이 없으면 NULL입니다. 원문 반환 설명의 앞쪽 ‘0’ 표기는 생성 문서 그대로의 오기입니다.

void sys_multi_heap_free(struct sys_multi_heap *mheap, void *block)

성공한 sys_multi_heap_alloc() 또는 sys_multi_heap_aligned_alloc()이 반환한 block을 원래 backend에 돌려줍니다. NULL block은 허용되며 아무 효과가 없습니다.

매개변수

  • mheap: multi-heap pointer
  • block: multi-heap에서 할당한 block 또는 NULL
struct sys_multi_heap_rec

등록된 child sys_heap과 user_data를 나타내는 multi-heap record입니다. 선언은 에 있습니다.

struct sys_multi_heap

여러 sys_heap backend와 choice callback을 묶는 wrapper object입니다. 선언은 에 있습니다.

힙 리스너

Heap listener는 allocation, free, resize 같은 heap event를 heap identifier별로 관찰하는 callback layer입니다. Listener object를 global 목록에 등록하면 해당 heap implementation이 notify 함수를 호출할 때 matching event만 전달받습니다.

리스너 API: heap_listener_apis

HEAP_ID_FROM_POINTER(heap_pointer)

sys_heap 같은 heap object pointer에서 heap identifier를 만듭니다.

매개변수

  • heap_pointer: heap object pointer
HEAP_ID_LIBC

Global libc heap을 식별하는 identifier입니다.

HEAP_LISTENER_ALLOC_DEFINE(name, _heap_id, _alloc_cb)

Allocation event용 heap listener node를 정의합니다.

void on_heap_alloc(uintptr_t heap_id, void *mem, size_t bytes)
{
  LOG_INF("Memory allocated at %p, size %ld", mem, bytes);
}

HEAP_LISTENER_ALLOC_DEFINE(my_listener, HEAP_ID_LIBC, on_heap_alloc);

매개변수

  • name: listener object 이름
  • _heap_id: 관찰할 heap identifier
  • _alloc_cb: allocation event 때 호출할 함수
HEAP_LISTENER_FREE_DEFINE(name, _heap_id, _free_cb)

Free event용 heap listener node를 정의합니다.

void on_heap_free(uintptr_t heap_id, void *mem, size_t bytes)
{
  LOG_INF("Memory freed at %p, size %ld", mem, bytes);
}

HEAP_LISTENER_FREE_DEFINE(my_listener, HEAP_ID_LIBC, on_heap_free);

매개변수

  • name: listener object 이름
  • _heap_id: 관찰할 heap identifier
  • _free_cb: free event 때 호출할 함수
HEAP_LISTENER_RESIZE_DEFINE(name, _heap_id, _resize_cb)

Heap resize event용 listener node를 정의합니다.

void on_heap_resized(uintptr_t heap_id, void *old_heap_end, void *new_heap_end)
{
  LOG_INF("Libc heap end moved from %p to %p", old_heap_end, new_heap_end);
}

HEAP_LISTENER_RESIZE_DEFINE(my_listener, HEAP_ID_LIBC, on_heap_resized);

매개변수

  • name: listener object 이름
  • _heap_id: 관찰할 heap identifier
  • _resize_cb: 관찰 heap 크기가 바뀔 때 호출할 함수
typedef void (*heap_listener_resize_cb_t)(uintptr_t heap_id, void *old_heap_end, void *new_heap_end)

Heap 크기 변경 때 호출되는 callback type입니다. Minimal C library는 이 event를 발생시키지 않습니다.

매개변수

  • heap_id: 크기가 바뀐 heap identifier
  • old_heap_end: 변경 전 heap 끝 pointer
  • new_heap_end: 변경 후 heap 끝 pointer
typedef void (*heap_listener_alloc_cb_t)(uintptr_t heap_id, void *mem, size_t bytes)

Heap allocation 때 호출되는 callback type입니다. Zephyr main repository 밖의 library가 관리하는 heap은 이 event를 내지 않을 수 있고, 내부 granularity 때문에 bytes가 application 요청과 정확히 같지 않을 수 있습니다.

매개변수

  • heap_id: heap identifier
  • mem: 할당 memory pointer
  • bytes: 실제 할당 memory 크기
typedef void (*heap_listener_free_cb_t)(uintptr_t heap_id, void *mem, size_t bytes)

Heap memory가 해제될 때 호출되는 callback type입니다. 외부 library heap은 event를 내지 않을 수 있고, 내부 allocation/free 방식 때문에 bytes가 원래 요청과 정확히 같지 않을 수 있습니다.

매개변수

  • heap_id: heap identifier
  • mem: 해제 memory pointer
  • bytes: 해제 memory 크기
enum heap_event_types

Heap listener가 구분하는 event 종류입니다.

HEAP_EVT_UNKNOWN = 0

알 수 없거나 초기 상태인 event 값입니다.

HEAP_RESIZE

Heap 범위가 바뀐 event입니다.

HEAP_ALLOC

Memory allocation event입니다.

HEAP_FREE

Memory free event입니다.

HEAP_REALLOC

Memory reallocation event입니다.

HEAP_MAX_EVENTS

Heap event enum의 상한 marker입니다.

void heap_listener_register(struct heap_listener *listener)

Listener를 global heap-listener 목록에 추가해 matching heap event 알림을 받게 합니다.

매개변수

  • listener: 등록할 heap_listener object pointer
void heap_listener_unregister(struct heap_listener *listener)

Listener를 global 목록에서 제거해 더는 알림을 받지 않게 합니다.

매개변수

  • listener: 해제할 heap_listener object pointer
void heap_listener_notify_alloc(uintptr_t heap_id, void *mem, size_t bytes)

일치하는 heap identifier를 관찰하는 listener에게 allocation 완료를 알립니다.

매개변수

  • heap_id: heap identifier
  • mem: 할당 memory pointer
  • bytes: 할당 memory 크기
void heap_listener_notify_free(uintptr_t heap_id, void *mem, size_t bytes)

일치하는 listener에게 heap memory 해제를 알립니다.

매개변수

  • heap_id: heap identifier
  • mem: 해제 memory pointer
  • bytes: 해제 memory 크기
void heap_listener_notify_resize(uintptr_t heap_id, void *old_heap_end, void *new_heap_end)

일치하는 listener에게 heap 범위 변경을 알립니다.

매개변수

  • heap_id: heap identifier
  • old_heap_end: 변경 전 heap 끝 주소
  • new_heap_end: 변경 후 heap 끝 주소
struct heap_listener

등록할 heap event listener object입니다. 선언은 에 있습니다.

sys_snode_t node

Global listener singly linked list에 연결하는 node입니다.

uintptr_t heap_id

관찰 대상 heap identifier입니다. Object로 표현되는 heap이면 heap pointer이고 global libc heap이면 0입니다.

enum heap_event_types event

알림 받을 heap event 종류입니다.

Source

출처

영어 원문에는 문단, 문서 지시문, 표, 코드, 코드 심벌, 경로를 그대로 보존했습니다.