운영체제는 메모리(RAM)를 한 바이트씩 다루지 않는다. 너무 비효율적이기 때문이다. 대신 메모리를 일정한 크기의 고정된 덩어리로 잘라서 관리하는데, 이 덩어리 하나를 페이지(page)라고 부른다. 그리고 그 덩어리의 크기가 페이지 크기(page size)다.
비유하자면 메모리는 한 권의 책이고, OS는 책을 한 글자씩 읽는 게 아니라 페이지 단위로 넘기며 읽는다. OS 입장에서 메모리 관리의 최소 단위가 곧 페이지인 셈이다.
페이지라는 단위가 존재하는 이유는 크게 두 가지다.
지금까지 대부분의 안드로이드(ARM64) 기기는 페이지 크기를 4KB로 써왔다. 오랫동안 이게 표준이었다.
그런데 기기에 탑재되는 RAM이 점점 커지면서, 더 큰 페이지 크기인 16KB를 쓰는 방향으로 바뀌고 있다. Android 15(API 35)부터 AOSP가 16KB 페이지를 정식 지원한다.
페이지 크기를 키우면 얻는 이점은 이렇다.
원리는 단순하다. 페이지가 커지면 CPU가 자잘한 메모리 조각을 일일이 관리하는 데 드는 오버헤드가 줄고, 그만큼 실제 작업에 자원을 더 쓸 수 있다.
단점도 있다. 페이지가 커지면 작은 메모리를 요청해도 최소 16KB 페이지 하나를 통째로 차지하므로, 평균적으로 메모리를 약간 더 쓴다.
여기가 핵심이다. 순수 JavaScript만으로 이루어진 앱은 페이지 크기와 무관하다. 페이지 정렬은 어디까지나 네이티브 바이너리(.so 파일) 수준의 이야기이기 때문이다.
문제는 React Native 앱이 결코 순수 JS가 아니라는 점이다. RN 앱은 다음과 같은 네이티브 라이브러리(.so)를 잔뜩 포함한다.
libhermes.so)libreactnative.so 등)이 .so 파일들이 4KB 페이지를 가정하고 정렬(alignment)된 채로 빌드되어 있으면, 16KB 페이지를 쓰는 기기에서 제대로 로드되지 못하거나 크래시(segmentation fault)가 날 수 있다.
즉, RN 앱의 16KB 대응이란 결국 "앱 안에 들어있는 모든 .so 파일이 16KB 정렬로 빌드되어 있는가" 의 문제다.
.so 파일을 메모리에 올릴 때, OS는 파일의 각 세그먼트(LOAD section)를 페이지 경계에 맞춰 배치한다. 이때 세그먼트의 시작 주소가 페이지 크기의 배수여야 깔끔하게 들어맞는다. 이것을 "정렬되어 있다"고 표현한다.
4KB의 배수가 항상 16KB의 배수인 것은 아니다. 그래서 4KB로 정렬된 .so는 16KB 기기에서 경계가 어긋난다. APK Analyzer나 빌드 도구에서 다음과 같은 경고가 뜨는 이유가 바로 이것이다.
4 KB LOAD section alignment, but 16 KB is required
이 경고는 앱 다운로드 용량과는 전혀 무관하다. 오로지 네이티브 라이브러리의 메모리 정렬에 관한 이야기다.
구글은 이 변화에 맞춰 정책을 도입했다.
대응하지 않으면 해당 마감 이후 앱 업데이트를 게시할 수 없게 된다. 버그 수정도, 신규 기능도, 보안 패치도 올릴 수 없다는 뜻이다.
다행히 RN은 16KB 페이지를 이미 공식 지원한다. 대응의 본질은 결국 버전 업그레이드와 재빌드다.
React Native 버전 업그레이드
RN은 0.75.3부터 16KB를 지원하기 시작했으며, 0.76 이상(New Architecture 기본)으로 올리는 것이 가장 안전하다.
빌드 툴체인 업데이트
이 버전들은 빌드 시 16KB 정렬을 자동으로 처리해준다.
서드파티 네이티브 모듈 최신화
네이티브 코드를 포함한 라이브러리(Reanimated, MMKV 등)를 16KB 호환 버전으로 올린다. 보통 라이브러리 메이저/마이너 버전 업으로 해결된다.
실제 16KB 환경에서 동작을 검증하는 것이 가장 확실하다.
adb shell getconf PAGE_SIZE
# 4096 또는 16384 출력