28.3.3.1. 힙(Heap) 파편화 방지를 위한 task_union 메모리 정적 할당(Static Allocation) 모델
조종사가 스위치를 튕길 때마다 수동 비행, 자동 비행, 복귀 비행 모드들이 수시로 켜지고 꺼진다. 이처럼 객체가 쉴 새 없이 생성되고 파괴되는 환경에서 앞서 언급한 힙(Heap) 메모리 파편화를 막기 위해, PX4의 FlightModeManager 클래스 내부에는 극단적이고도 눈물겨운 C++ 메모리 트릭이 숨어 있다.
그 핵심이 바로 모든 비행 태스크의 메모리 크기를 하나로 통일해 버리는 task_union (또는 Aligned Storage) 기법이다.
1. C++ 공용체(union)를 활용한 메모리 공간의 찜(Pre-allocation)
수많은 FlightTask 자식 클래스들은 각자 품고 있는 멤버 변수의 개수나 배열의 크기가 다르기 때문에 메모리 크기가 제각각이다. 어떤 클래스는 120바이트, 어떤 클래스는 350바이트를 차지할 수 있다.
PX4 개발자들은 런타임에 동적으로 공간을 구걸하는 대신 로딩 타임(Compile/Boot time)에 가장 거대한 클래스의 크기만큼 미리 땅을 사버리는 전략을 취했다.
// FlightModeManager.hpp 내부의 메모리 할당 의사 코드 개념
union TaskUnion {
FlightTaskManual manual_task;
FlightTaskAutoMapper auto_mapper_task;
FlightTaskOrbit orbit_task;
// ... 모든 FlightTask 자식 클래스들을 나열
};
// 런타임 힙이 아닌 정적 배열 형태의 바이트(Byte) 블록 선언
alignas(TaskUnion) uint8_t _task_memory[sizeof(TaskUnion)];
- 최대 크기 보장(Max Size Guarantee):
C++ 컴파일러는 위와 같은 코드 구문을 만나면, 나열된 태스크 클래스들 중 가장 덩치가 큰 녀석(예: 복잡한 수학 매트릭스를 들고 있는FlightTaskAutoMapper가 400바이트라면 400바이트)의 크기를 계산하여 정확히 400바이트짜리 연속된 단일 메모리 블록(_task_memory)을 떡하니 예약해 버린다. - 스위스 치즈 방지:
이 400바이트 공간은 FMM 데몬이 시작될 때 단 한 번만 할당되며 기체가 꺼질 때까지 절대 반환되지 않는다. 어떠한 비행 모드가 켜지든 무조건 이 미리 확보된 400바이트짜리 방 안에서만 놀아야 하므로, 힙 메모리에 구멍이 뚫리는 파편화(Fragmentation) 현상은 원천적으로 발생할 수 없다.
2. 정적 할당(Static Allocation)이 가져온 임베디드 안정성 결실
이 정적 할당 아키텍처는 메모리가 매우 쪼들리는 Pixhawk의 STM32 마이크로컨트롤러 환경에서 기적과도 같은 안정성을 뽑아낸다.
- 결정론적(Deterministic) 자원 관리: 비행 중 모드 스위치를 10만 번을 딸깍거리든 100만 번을 딸깍거리든, FMM 데몬의 RAM 점유율은 단 1바이트도 늘어나지 않는다 (메모리 누수 Free).
- 하드 폴트(Hard-fault)의 제거: 더 이상
new연산자가 빈 메모리를 찾지 못해 커널 패닉을 일으키며 기체를 추락시킬 위험이 통계적으로 0%가 된다.
운영체제(NuttX RTOS) 입장에서도 FMM 데몬은 항상 예의 바르게 고정된 크기의 지분만 차지하고 있는 모범적인 스레드(Thread)로 보이게 되며, 이는 전체 비행 제어 스택의 신뢰성을 항공 우주 등급으로 끌어올리는 숨은 일등 공신이라 할 수 있다.
이제 미리 확보한 이 빈방(_task_memory)에 구체적으로 어떻게 모드들을 번갈아 가며 입주시키는지, 다음 장의 Placement new 메커니즘을 통해 알아보자.