피드로 돌아가기
Dev.toInfrastructure
원문 읽기
심볼 가시성 설정 누락으로 인한 React Native 바이너리 94% 낭비 확인
React Native Exports 2,826 Symbols. Your App Needs 45.
AI 요약
Context
React Native Android 앱의 libreactnative.so 라이브러리가 불필요한 Dynamic Symbol을 대량으로 Export하는 구조적 결함 존재. PGO, LTO 등 고도화된 최적화 파이프라인을 적용했음에도 불구하고, 컴파일러 플래그 설정 미비로 인해 내부 구현 상세가 외부로 노출되는 현상 발생.
Technical Solution
- nm -D 도구를 통한 Production APK 내 .so 파일의 Exported Symbol 전수 조사
- 실제 다른 라이브러리에서 참조하거나 JNI를 통해 호출되는 필수 심볼(약 420개)과 전체 심볼(6,762개)의 교차 검증을 통한 낭비율 산출
- -fvisibility=hidden 플래그 미적용으로 인해 내부 클래스 메서드 및 Yoga C API, Chrome DevTools Inspector 등 불필요한 심볼이 Linker의 Stripping 대상에서 제외되는 메커니즘 파악
- SampleCxxModule과 같은 데모 코드가 Production 빌드에 포함되어 바이너리 크기를 증가시키는 병목 지점 식별
- 실제 소비되는 심볼만 정의하는 Version Script 작성을 통해 필요한 API Surface만 노출하는 최적화 방향 제시
Impact
- libreactnative.so 기준 전체 심볼의 약 83%~94%가 불필요한 Waste로 확인
- 심볼 가시성 최적화 시 라이브러리당 약 1.2MB ~ 2.4MB의 바이너리 크기 절감 가능
- Discord의 특정 Rust 기반 모듈(.so)에서 최대 99%의 심볼 낭비율 측정
Key Takeaway
복잡한 Post-link 최적화 알고리즘보다 컴파일러의 기본 가시성 설정(-fvisibility)과 같은 근본적인 빌드 설정 검증이 바이너리 효율성에 더 결정적인 영향을 미침.
실천 포인트
- Production 빌드 시 `-fvisibility=hidden` 플래그 적용 여부 확인 - `nm -D` 또는 `readelf`를 사용하여 배포 바이너리의 Symbol Table 내 불필요한 Public API 노출 여부 감사 - 라이브러리 설계 시 외부 노출이 필요한 API만 명시적으로 정의하는 Version Script 도입 검토 - 데모 코드나 디버그용 서브시스템이 Conditional Compilation을 통해 완전히 제거되었는지 검증