28.3.3. 메모리 최적화 및 인스턴스 라이프사이클 관리
PX4가 구동되는 Pixhawk 같은 임베디드 비행 제어기(FC) 하드웨어는 우리가 쓰는 데스크탑 PC와는 근본적으로 다른 척박한 세계다. 기껏해야 수백 킬로바이트(KB) 남짓한 코어 SRAM(Static RAM)만을 가지고 수호지 108번뇌에 맞먹는 그 수많은 비행 모드 클래스들을 모두 구동해야 한다.
따라서 Flight Mode Manager(FMM) 모듈은 이 수십 개의 FlightTask 자식 클래스들을 모두 한 번에 메모리에 부팅시키는 미친 짓을 하지 않는다. 대신, 한 번에 오직 단 하나의 비행 모드 객체만을 살려두는 극단적인 단일 인스턴스 라이프사이클(Single Instance Lifecycle) 구조를 취하고 있다.
1. 생성과 파괴의 철저한 생명주기 (Creation and Destruction)
조종사가 조종기 스위치를 딸깍! 하고 수동 비행에서 자동 미션 비행으로 전환하는 순간, FMM의 심장부인 switchTask() 함수 내부에서는 거대한 세대교체가 일어난다.
- 즉각적인 파괴(Destruction):
FMM은 현재 구동 중이던FlightTaskManual객체의 소멸자(Destructor)를 즉각 호출하여 메모리상에서 객체를 흔적도 없이 파괴(Kill)시켜 버린다. 이 파괴 과정에서 해당 모드가 점유하고 있던 uORB 구독자(Subscriber)나 타겟 임시 변수들이 뱉어낸 자원들이 OS에 반환된다. - 새로운 생성(Creation):
이전 객체의 파괴가 확정되고 나서야 비로소FlightTaskAutoMission객체의 생성자(Constructor)가 호출되며, 빈 메모리 터전에 새집을 짓고activate()가상 함수를 통해 새로운 모드가 부팅을 시작한다.
이처럼 무자비할 정도로 철저한 파괴와 생성 루틴 덕분에, PX4는 비행 모드가 100개가 생기든 1000개가 생기든 펌웨어 용량만 차지할 뿐, 실제 구동 시 사용하는 RAM 메모리의 총량은 가장 덩치가 큰 비행 모드 하나를 구동할 용량을 절대 넘지 않는 완벽한 O(1) 메모리 점유율을 자랑하게 된다.
2. 동적 할당(Dynamic Allocation)의 치명적 부작용: 힙 파편화(Heap Fragmentation)
하지만 위의 “객체를 하나만 살린다“는 철학을 C++의 일반적인 new / delete 동적 할당 연산자로 구현하면 임베디드 시스템에서는 매우 치명적인 문제인 힙 파편화(Heap Fragmentation) 에 직면하게 된다.
- 예를 들어, 100바이트 크기의 수동 모드를 지우고 그 자리에 120바이트 크기의 자동 모드를
new로 할당하면, OS의 힙(Heap) 메모리 관리자는 여기저기 흩어진 메모리 구멍(Hole)들 사이에서 간신히 120바이트 연속 공간을 찾아 집어넣는다. - 조종사가 비행 모드를 수백 번 켰다 껐다 반복하면 힙 메모리는 마치 스위스 치즈처럼 구멍이 송송 뚫리게 되고, 결국 전체 메모리는 충분히 남아있는데 120바이트짜리 ’연속된 공간’을 찾지 못해
new연산자가 영구적인 하드-폴트(Hard-fault) 에러를 뿜으며 기체가 추락하게 된다.
3. 정적 메모리 예약(Static Pre-allocation)을 향한 아키텍처 진화
PX4 설계자들은 이러한 임베디드 OS 고유의 힙 파편화 추락 위험을 근본적으로 제거하기 위해, FMM 내부에 아예 new와 delete를 거치지 않고 미리 비행 모드용으로 거대한 단일 메모리 블록을 찜(Pre-allocation)해두는 극단적인 최적화 구조를 도입했다.
이 C++ 메모리 최적화의 정수가 바로 다음 섹션에서 설명할 C++ union 공용체 기법과 Placement new 연산자의 기가 막힌 조합이다.