실시간 메모리 요구사항 — Determinism·Fragmentation·WCET
#한 줄 요약
“RT 시스템에서는 allocation 시간이 bounded해야 합니다.”
malloc의 가변 시간은 deadline을 위협합니다.
#일반 malloc의 문제
void *ptr = malloc(1024);내부에서는 다음과 같은 단계가 일어납니다.
- Size class별 free list를 순회합니다.
- Block을 split합니다.
- Coalesce 가능 여부를 검사합니다.
- Heap lock을 acquire합니다.
그 결과 실행 시간이 수 µs에서 수 ms까지 들쭉날쭉합니다. WCET 보장이 어려워집니다.
#Fragmentation
#External Fragmentation
Free 영역: ████░░██░░███░░██ (총 free 6KB)요청: [████████] (8 KB 연속)→ 6 KB free 있어도 *연속 8 KB 없음* → 할당 실패총 free 메모리가 충분해도 연속 영역이 부족해 할당이 실패하는 상황입니다.
#Internal Fragmentation
요청: 100 byte할당: 128 byte block (size class) → 28 byte 낭비Size class에 맞춰 올림 할당하면서 발생하는 낭비입니다.
#RT 시스템의 메모리 전략
| 전략 | 장점 | 단점 |
|---|---|---|
| No malloc | WCET 보장, 가장 안전 | 유연성 ↓ |
| Static allocation | 초기화 시 결정 | 메모리 oversized |
| Memory pool | O(1) alloc/free | 크기별 고정 |
| TLSF | O(1) bounded | 약간 복잡 |
| Heap_4 (FreeRTOS) | first-fit | non-bounded WCET |
| Heap_5 (FreeRTOS) | non-contiguous | first-fit |
#Safety-Critical Standards
| 표준 | 영향 |
|---|---|
| MISRA C | Rule 21.3 — malloc/free 사용 금지 (Dir 4.12) |
| DO-178C | Level A·B에 dynamic allocation 회피 |
| CERT C | MEM34-C — realloc 후 NULL 검사 |
| AUTOSAR | Static allocation 우선 |
| ISO 26262 | ASIL-D에 dynamic 자제 |
#Bounded Allocator — TLSF
Two-Level Segregated Fit (Masmano 2004):
First level — size 2^n bucket (16, 32, 64, ..., 64K)Second level — 각 bucket을 2^m sub-bucket e.g. 2 KB bucket → 2k, 2.25k, 2.5k, 2.75k
allocate(size): - first level idx = floor(log2(size)) - second level idx = (size - 2^fl) / (2^(fl-4)) - bitmap에서 *가장 가까운 큰 bucket* 찾음 (CLZ) - O(1)자세한 내용은 4-03 편에서 다룹니다.
#Static Allocation 패턴
static uint8_t task1_stack[2048];static StaticTask_t task1_tcb;
TaskHandle_t xTaskCreateStatic( task1_function, "task1", 2048 / sizeof(StackType_t), NULL, 5, task1_stack, &task1_tcb);FreeRTOS, Zephyr, Wind River 모두 static variant API를 제공합니다.
#Memory Pool
#define POOL_SIZE 32#define BLOCK_SIZE 64
static uint8_t pool_buf[POOL_SIZE * BLOCK_SIZE];static struct { uint8_t *free_list; mutex_t lock; } pool;
void *pool_alloc(void) { /* O(1) — free list pop */}void pool_free(void *ptr) { /* O(1) — free list push */}Block 크기를 고정해 fragmentation이 0이 되고 WCET도 보장됩니다.
#Buddy Allocator
Linux 커널과 일부 RTOS에서 사용하는 방식입니다.
초기: [ 2MB ]요청 256KB: [256K][256K][512K][1M] 할당하나 free 3개Power-of-2 단위로 split하고 coalesce하므로 bounded O(log N)을 보장합니다.
#측정: Heap 상태
/* FreeRTOS */size_t free = xPortGetFreeHeapSize();size_t min = xPortGetMinimumEverFreeHeapSize();HeapStats_t stats;vPortGetHeapStats(&stats);/* stats.xMaximumFreeBlockSize, xNumberOfFreeBlocks */xMaximumFreeBlockSize가 작은데 xNumberOfFreeBlocks가 많으면 fragmentation이 심하다는 신호입니다.
#Embedded에서 DRAM과 SRAM 분리
__attribute__((section(".dtcm"))) uint8_t fast_buf[8192]; /* TCM */__attribute__((section(".sdram"))) uint8_t big_buf[256 * 1024]; /* ext SDRAM */__attribute__((section(".sram"))) uint8_t medium_buf[16384];Memory region마다 속도와 용량의 trade-off가 다릅니다. Linker script로 영역을 명시합니다.
#자동차와 항공: Static Only
ASIL-D ECU에서는
- 모든 task stack을 static으로 둡니다.
- 모든 buffer를 compile-time fixed로 잡습니다.
- 모든 message queue를 static으로 만듭니다.
- malloc 자체를 제외합니다.
KSLV-II 누리호 flight computer에는 malloc이 아예 없습니다. 모든 메모리는 부팅 시점에 고정됩니다.
#DO-178C Level A에서 Heap 사용
가능은 하지만 극도로 어렵습니다.
- WCET 분석
- Worst-case fragmentation 증명
- 모든 path coverage
- Robustness testing
이 모든 항목을 증명하는 비용이 크기 때문에 보통은 heap을 피합니다. ITAR이나 NIST 같은 표준도 같은 방향을 권장합니다.
#자주 하는 실수
⚠️ Production 코드에서 heap을 안일하게 사용하는 경우
/* Production code에 */void *buf = malloc(rand() % 1024);Embedded 환경에서는 malloc 자체를 피하는 편이 안전합니다.
⚠️ Fragmentation을 인지하지 못하는 경우
malloc(100); free();malloc(200); free();malloc(50); free();/* → free list 흩어짐 */malloc(150); /* ← 가능하나 fragmented free 영역 search */이 패턴이 반복되면 free list가 흩어집니다. memory pool이나 TLSF로 대체해야 합니다.
⚠️ Stack을 dynamic하게 할당하는 경우
xTaskCreate(... uxStackDepth ... );/* → heap에서 stack 할당 */대신 xTaskCreateStatic을 사용합니다.
⚠️ ISR에서 malloc을 호출하는 경우
ISR: malloc(...); /* ✗ heap lock — deadlock */ISR에서는 static buffer만 사용해야 합니다.
#정리
- RT 메모리는 bounded allocation과 no fragmentation을 동시에 충족해야 합니다.
- Safety-critical 표준(MISRA, DO-178C, ASIL)에서는
malloc을 금지하거나 회피합니다. - 대안으로 static 할당, memory pool, TLSF, buddy allocator가 있습니다.
- 상태 측정은 FreeRTOS의
vPortGetHeapStats로 확인합니다. - 발사체나 자동차 ECU는 거의 static-only로 운영합니다.
다음 편에서는 FreeRTOS Heap_1부터 Heap_5까지 다섯 가지 구현을 비교합니다.
#관련 항목
Practical RTOS Internals · 34 of 53
- 1Practical RTOS Internals — 실시간 커널 내부 분석 시리즈 소개
- 2RTOS가 필요한 이유 — 일반 OS와의 결정적 차이
- 3Task와 Thread 개념 — TCB·상태 머신·생명 주기 분석
- 4실시간 스케줄링 알고리즘 비교 — RR·Priority·EDF·RMS
- 5Preemption과 Cooperation — 강제 전환 vs 자발 양보
- 6인터럽트와 RTOS — ISR Context·Deferred Processing·FromISR API
- 7동기화 기초 분석 — Critical Section·Mutual Exclusion·Race Condition
- 8Semaphore 개념 분해 — Counting·Binary·P/V 연산
- 9Mutex 개념 분해 — Ownership·Recursive·Priority Inheritance
- 10큐와 메시지 패싱 — Producer-Consumer·Ring Buffer·전달 의미
- 11실시간성 분석 — Latency·Jitter·Deadline·WCET·RMA
- 12Ready List 자료구조 분석 — Linked List·Bitmap·O(1) Scheduler
- 13Blocked List 자료구조 — Timeout 정렬·Delta List·Two-List Scheme
- 14Scheduler 알고리즘 구현 추적 — Next-Task Selection 로직
- 15Context Switch 원리 분석 — 레지스터 저장·복원·Stack Frame
- 16ARM Cortex-M Context Switch — PendSV·MSP/PSP 어셈블리 추적
- 17ARM Cortex-A Context Switch — Mode 전환·SVC·Banked Registers
- 18RISC-V Context Switch 분석 — ECALL·mret·CSR
- 19RTOS Tick과 타이머 — SysTick·Generic Timer·configTICK_RATE_HZ
- 20Tickless 모드 구현 — Idle Tick Suppression·Sleep·Wake 보정
- 21Scheduler Latency 측정 기법 — GPIO Toggle·DWT·ftrace·cyclictest
- 22RTOS Tracing과 Observability — Tracealyzer·SystemView·ITM/ETM
- 23Critical Section 구현 비교 — IRQ Disable·BASEPRI·Spinlock
- 24Semaphore 내부 구현 추적 — Counter·Wait List·ISR-Safe Variant
- 25Mutex 내부 구현 추적 — Owner·Recursion Count·ISR 금지
- 26Priority Inversion 문제 — Mars Pathfinder 사례·Bounded vs Unbounded
- 27Priority Inheritance 구현 — Inherit·Disinherit·Chain
- 28Priority Ceiling Protocol — Immediate vs Original 비교
- 29Queue 내부 구현 추적 — Ring Buffer·2 Wait Lists·Atomic Send/Receive
- 30Event Group 분석 — Bit Flag·AND/OR Wait·Sync Barrier
- 31ISR-Safe API 설계 — FromISR 패턴·Higher Priority Wake·Deferred Work
- 32Deadlock 분석 — 4 조건·Wait-for Graph·Lock Ordering·Timeout
- 33Stream Buffer와 Message Buffer — FreeRTOS 10의 Lock-Free SPSC
- 34실시간 메모리 요구사항 — Determinism·Fragmentation·WCET
- 35FreeRTOS Heap_1~5 분석 — 5종 Allocator의 구조와 트레이드오프
- 36TLSF Allocator 분석 — Two-Level Segregated Fit O(1)
- 37Static Allocation — 컴파일 타임으로 동적 위험 제거하기
- 38Memory Pool — Fixed-Size Block Allocator의 단순함과 강력함
- 39Stack Overflow 탐지 — Canary·MPU·Watermark 3중 방어
- 40SMP RTOS 설계 — Ready List·Affinity·IPI·Load Balancing
- 41SMP Spinlock 구현 — LDREX/STREX·Ticket Lock·MCS·WFE/SEV
- 42Software Timer 분석 — Daemon Task·자료구조·ISR-Safe API
- 43RTOS System Call — SVC·ECALL·User/Kernel 분리·FreeRTOS-MPU
- 44TrustZone과 TF-M — Secure/Non-Secure·NSC Veneer·PSA
- 45AMP와 OpenAMP — Heterogeneous SoC·RPMsg·remoteproc
- 46C++ in RTOS — RAII·std::thread·ETL·Coroutine
- 47FreeRTOS 소스 분석 — tasks.c·queue.c·port.c 추적
- 48Zephyr 커널 분석 — k_thread·k_sem·Driver Model
- 49RT-Thread 분석 — Object 모델·Components·Smart·Studio
- 50RTOS 포팅 가이드 — 새 아키텍처에 옮기는 절차
- 51RTOS 선택 가이드 — Footprint·License·Certification·Ecosystem
- 52Apache NuttX 분석 — POSIX·PX4·NASA Ingenuity
- 53PREEMPT_RT Linux — Mainline 6.12·Xenomai 4·EVL
관련 글
실시간성 분석 — Latency·Jitter·Deadline·WCET·RMA
4 핵심 지표인 Latency, Jitter, Deadline, WCET를 다룹니다. Hard와 Soft real-time의 차이, Rate Monotonic Analysis로 schedulability를 증명하는 방법을 살펴봅니다.
PREEMPT_RT Linux — Mainline 6.12·Xenomai 4·EVL
2024년 9월 Linux 6.12 mainline에 합류한 PREEMPT_RT의 핵심 변경을 정리하고, Xenomai 4·EVL과 함께 RTOS와의 선택 기준을 비교합니다. threaded IRQ·sleeping spinlock·cyclictest까지 한 지도에 모읍니다.
Apache NuttX 분석 — POSIX·PX4·NASA Ingenuity
NuttX의 POSIX-compliant 구조를 따라가며 PX4 autopilot과 NASA Ingenuity 화성 헬리콥터 채택 배경을 정리합니다. Flat/Protected/Kernel 빌드, VFS, 네트워크, NSH, micro-ROS 통합까지 한 지도로 모읍니다.
이 글을 참조하는 글 (6)
- Stack Overflow 탐지 — Canary·MPU·Watermark 3중 방어— Practical RTOS Internals
- Memory Pool — Fixed-Size Block Allocator의 단순함과 강력함— Practical RTOS Internals
- Static Allocation — 컴파일 타임으로 동적 위험 제거하기— Practical RTOS Internals
- TLSF Allocator 분석 — Two-Level Segregated Fit O(1)— Practical RTOS Internals
- FreeRTOS Heap_1~5 분석 — 5종 Allocator의 구조와 트레이드오프— Practical RTOS Internals
- 임베디드 동적 메모리 — malloc 위험·결정성·대안 분석— Modern Embedded Recipes