35.2.1.2. 동적 링킹(Dynamic Linking)과 정적 링킹(Static Linking) 환경에서의 런타임 메모리 단편화(Memory Fragmentation) 오버헤드 비교
MAVSDK C++ 코어나 PX4 임무 컴퓨터(Companion Computer) 애플리케이션을 크로스 컴파일(Cross-compile)할 때, 개발자는 최종 산출물의 형태를 동적 공유 라이브러리(Dynamic Shared Library, .so)로 구성할 것인지 정적 라이브러리(Static Library, .a) 베이스의 단일 실행 파일로 구성할 것인지를 선택해야 한다. 데스크톱 환경에서는 명확한 정답이 정해져 있으나, 가용 RAM이 512\text{MB} 미만으로 극도로 제한된 소형 임베디드 환경에서는 이 링킹(Linking) 전략이 실시간 운영 체제(RTOS) 커널의 런타임 메모리 단편화(Memory Fragmentation)에 치명적인 영향을 미친다. 본 절에서는 두 링킹 환경의 근본적인 오버헤드를 비교 분석한다.
1. 정적 링킹(Static Linking)과 단일 주소 공간(Single Address Space)의 견고성
정적 링킹은 libmavsdk.a 내부에 컴파일된 모든 목적 코드(Object Code)를 링커(Linker)가 가져와 최종 애플리케이션인 하나의 커다란 vtol_controller 실행 파일 안에 완전히 우겨넣는 방식이다.
- 메모리 배치(Layout)의 확정성: 프로그램이 커널에 의해 적재(Load)될 때, BSS(Block Started by Symbol) 세그먼트, 데이터(Data) 세그먼트, 텍스트(Text) 세그먼트의 크기가 런타임 이전에 정확하게 바이트 단위로 고정되어 있다.
- 단편화(Fragmentation) 억제: 프로세스가 실행되는 내내 추가적인 공유 라이브러리를 로딩하기 위한 힙(Heap) 영역 확장이 불필요하므로, 외부 단편화(External Fragmentation)가 사실상 원천 차단된다.
- L1/L2 캐시 최적화(Cache Locality): MAVLink 파싱 함수와 제어 루프 함수가 물리적으로 매우 가까운 메모리 주소(Address)에 인접하여 배치될 확률이 높아져 CPU 캐시 힛(Cache Hit)율이 비약적으로 상승한다.
2. 동적 링킹(Dynamic Linking)과 페이지 폴트(Page Fault)의 시간 지연 리스크
동적 링킹은 애플리케이션 바이너리를 수 킬로바이트 수준으로 경량화하고, libmavsdk.so 코어가 메모리에 한 번만 적재되면 여러 프로세스(예: QGroundControl 노드와 자율주행 노드가 동시 구동)가 해당 메모리 페이지(Page)를 공유할 수 있게 한다. 하지만 고주파 임베디드 제어 관점에서는 치명적인 리스크를 동반한다.
- 동적 로딩(Dynamic Loading) 오버헤드:
dlopen메커니즘을 통해 런타임에 심볼(Symbol) 매핑 테이블인 PLT(Procedure Linkage Table)와 GOT(Global Offset Table)를 해석(Resolve)하는 과정에서 간헐적인 지연(Latency)이 발생한다. - 메모리 단편화 병목: 여러 독립된 플러그인 모듈들이 동적으로 올라가고 내려가는 과정이 반복되면, RAM 상에 사용 가능한 빈 공간이 체스판처럼 잘게 쪼개지는 외부 단편화 현상이 일어난다.
- 메이저 페이지 폴트(Major Page Fault): 스왑(Swap) 공간에 내려간(Page-out된) 공유 라이브러리의 텍스트 세그먼트를 급하게 사용하기 위해 디스크에서 읽어 들이는 상황이 발생하면, 하드웨어 타이머에 동기화된 시스템의 역학 루틴이 수십에서 수백 밀리초 단위로 멈추는(Stall) 비극이 초래된다.
3. 성능 비교 요약 및 MAVSDK 코어 배포 전략
결과적으로 두 가지 텔레메트리 환경을 대상으로 한 런타임 시스템 오버헤드를 비교하면 다음과 같다.
| 지표 | 정적 링킹 (Static Linking) | 동적 링킹 (Dynamic/Shared Linking) |
|---|---|---|
| 바이너리 사이즈 | 큼 (일반적으로 \vert > 20\text{MB} \vert) | 매우 작음 (단, .so 파일 별도 존재) |
| 적재 시간 (Load Time) | 비교적 빠름 (1회 로딩 후 완료) | 느림 (심볼 테이블 런타임 해석 지연) |
| 메모리 단편화 리스크 | 거의 없음 (결정론적 메모리 모델) | 런타임 플러그인 구조 채택 시 높음 |
| 함수 호출(Call) 오버헤드 | 직접 점프(Direct Jump) 체계로 Zero-overhead | PLT/GOT 간접 참조 연산 패널티 구조 |
PX4 생태계에서 임무 컴퓨터(RASPI 등)를 타겟팅할 때 가장 권장되는 빌드 플래그는 BUILD_SHARED_LIBS=OFF(정적 링킹) 구도이다. 특히 다중 에이전트(Swarm) 제어와 같이 각 프로세스가 오직 자신만의 MAVLink 인스턴스를 격리된(Isolated) 메모리 공간 내에서 폭력적으로 처리해야 할 경우, 파일 시스템의 용량을 수십 메가바이트(MB) 더 희생하더라도 정적 링킹을 통한 메모리 단편화 회피와 캐시 친화성을 도모하는 것이 항공 안전 공학 측면에서 훨씬 우월한 전략으로 평가받는다.
4. 결론
임베디드 리눅스의 가상 메모리 관리(Virtual Memory Management) 체계 아래서 동적 링킹이 제공하는 프로세스 간 라이브러리 공유 패러다임은 디스크 스토리지 절감에 유효하다. 그러나 초당 수천 번의 루프(Loop)를 돌며 부동 소수점 행렬 연산을 수행하는 드론의 실시간 제어 스레드 환경에서는 티끌만 한 링커 테이블 해석 오버헤드와 캐시 미스(Cache Miss)마저 기피 대상이다. 즉, MAVSDK 네이티브 C++ 코어의 포팅 시에는 가급적 정적 링킹(Static Build) 파이프라인을 구축하여 런타임 메모리 단편화(Memory Fragmentation) 변수를 하드웨어 구조 설계 단계부터 근원적으로 도려내어야 한다.