React Native 0.84의 Hermes V1: 성능 최적화, 프리컴파일 바이트코드, 기술 면접 가이드
Hermes V1이 React Native 0.84의 기본 JavaScript 엔진으로 채택되어 바이트코드 프리컴파일, Hades 가비지 컬렉터, 메모리 최적화를 통해 획기적인 성능 향상을 제공합니다. 기술 면접에서 자주 출제되는 Hermes 내부 구조를 상세히 다룹니다.

2026년 2월에 출시된 React Native 0.84에서 Hermes V1이 기본 JavaScript 엔진으로 채택되었습니다. 이는 React Native 역사상 가장 중요한 성능 개선으로, 빌드 타임 바이트코드 컴파일, Hades 동시성 가비지 컬렉터, 메모리 최적화 전략을 통해 모바일 애플리케이션의 시작 속도와 실행 효율성을 크게 향상시킵니다.
Hermes V1은 빌드 타임 바이트코드 컴파일을 통해 Time to Interactive(TTI)를 2550% 단축합니다. 런타임 JavaScript 파싱을 제거하고, JavaScriptCore 대비 메모리 사용량을 1030% 감소시킵니다.
바이트코드 프리컴파일로 시작 오버헤드 제거하기
JavaScriptCore(JSC)나 V8과 같은 기존 JavaScript 엔진은 다단계 실행 파이프라인을 따릅니다. 소스 코드를 파싱하고, 추상 구문 트리(AST)를 생성하고, 바이트코드로 컴파일한 다음, 런타임에 핫 경로를 최적화합니다. Hermes는 이 접근 방식을 근본적으로 변경하여 컴파일을 빌드 타임으로 이동시켰습니다.
React Native 빌드 프로세스에서 Metro 번들러가 JavaScript 번들을 생성합니다. 그 후 Hermes 컴파일러(hermesc)가 이 번들을 최적화된 바이트코드로 변환하여 .hbc 파일로 저장합니다. 런타임에는 엔진이 프리컴파일된 바이트코드를 직접 로드하므로 파싱, AST 생성, JIT 웜업 지연이 발생하지 않습니다.
const { getDefaultConfig } = require('@react-native/metro-config');
const config = getDefaultConfig(__dirname);
// Hermes bytecode compilation is automatic in 0.84+
// The transformer handles .hbc generation during build
module.exports = {
...config,
transformer: {
...config.transformer,
// hermesParser is now the default
hermesParser: true,
// Inline requires reduce initial bundle evaluation time
inlineRequires: true,
},
};.hbc 파일은 mmap()을 사용하여 프로세스 주소 공간에 직접 메모리 매핑됩니다. 이를 통해 메모리 압박 상황에서 운영 체제가 사용하지 않는 바이트코드 세그먼트를 페이지 아웃할 수 있으며, Hermes가 JavaScript 소스를 다시 파싱할 필요가 없습니다. 메모리가 제한된 기기에서는 큰 번들을 사용하는 JSC에서 발생하던 메모리 부족 크래시를 방지합니다.
Hades: 동시성 가비지 컬렉터 아키텍처
Hermes V1은 싱글 스레드 GenGC를 대체하는 대부분 동시성으로 동작하는 세대별 가비지 컬렉터인 Hades를 사용합니다. Hades 내부 구조를 이해하는 것은 메모리 문제 디버깅과 시니어 레벨 기술 면접 질문에 답변하는 데 필수적입니다.
GenGC는 모든 가비지 컬렉션 작업을 메인 스레드에서 수행했기 때문에 눈에 띄는 UI 버벅거림을 유발했습니다. Facebook for Android와 같은 복잡한 앱에서 GenGC 일시 정지는 평균 200ms였으며, p99 지연 시간은 1.4초에 달했고, 저사양 기기에서는 7초까지 치솟기도 했습니다.
Hades는 컬렉션 작업의 대부분을 백그라운드 스레드에서 JavaScript 실행과 동시에 수행하여 이 문제를 해결합니다. 컬렉터는 올드 제너레이션에 대해 스냅샷 앳 더 비기닝(snapshot-at-the-beginning) 마크 스윕 전략을 사용하고, 영 제너레이션에 대해서는 세미스페이스 복사 전략을 유지합니다.
// Understanding allocation patterns that work well with Hades
// Short-lived objects in the young generation are collected quickly
function renderProductList(products) {
// Temporary array - young generation, fast collection
const mapped = products.map(product => ({
id: product.id,
display: `${product.name} - $${product.price}`,
}));
return mapped;
}
// Avoid patterns that defeat generational GC
// Don't cache large objects unnecessarily - they promote to old gen
const expensiveCache = {}; // Old generation - less frequent collection
// Instead, use bounded caches with explicit eviction
class BoundedCache {
constructor(maxSize = 100) {
this.maxSize = maxSize;
this.cache = new Map();
}
set(key, value) {
if (this.cache.size >= this.maxSize) {
// Evict oldest entry - allows GC to reclaim memory
const firstKey = this.cache.keys().next().value;
this.cache.delete(firstKey);
}
this.cache.set(key, value);
}
get(key) {
return this.cache.get(key);
}
}React Native는 프리테뉴어링(pre-tenuring)이 적용된 Hermes를 구성합니다. 첫 32MiB의 할당은 영 제너레이션 컬렉션을 건너뛰고 올드 제너레이션에 직접 배치됩니다. 앱 초기화 중에 할당되는 객체(내비게이션 스택, 글로벌 상태, API 클라이언트)는 일반적으로 오래 살아남으며, 젊은 객체가 빨리 죽는다는 세대 가설을 따르지 않습니다. 프리테뉴어링은 시작 시 불필요한 영 제너레이션 컬렉션을 피하여 TTI를 직접적으로 개선합니다.
Hermes V1을 위한 메모리 최적화 패턴
Hermes V1은 지연 함수 컴파일을 도입했습니다. 함수는 처음 호출될 때만 완전히 컴파일됩니다. 이를 통해 거의 사용되지 않는 코드 경로가 많은 코드베이스의 초기 메모리 풋프린트가 크게 감소하지만, 개발자는 그 영향을 이해해야 합니다.
// These functions compile only when the feature is accessed
export function initializeAdvancedAnalytics() {
// Complex initialization logic - compiled on first call
const analyticsEngine = require('./AnalyticsEngine');
return analyticsEngine.initialize({
samplingRate: 0.1,
batchSize: 50,
});
}
export function generateDetailedReport(data) {
// Heavy computation - memory allocated only when needed
const ReportGenerator = require('./ReportGenerator');
return new ReportGenerator(data).generate();
}
// In component - feature flags control compilation timing
function SettingsScreen({ hasAdvancedFeatures }) {
const [analytics, setAnalytics] = useState(null);
useEffect(() => {
if (hasAdvancedFeatures && !analytics) {
// Function compiles here, not at module load
setAnalytics(initializeAdvancedAnalytics());
}
}, [hasAdvancedFeatures]);
return (
<View>
{hasAdvancedFeatures && analytics && (
<AnalyticsDashboard data={analytics} />
)}
</View>
);
}Hermes 바이트코드는 일반적으로 동등한 미니파이된 JavaScript보다 10~30% 더 작습니다. 이러한 번들 크기 감소로 앱 스토어에서 다운로드부터 첫 실행까지의 전환율이 향상되고, 스토리지가 느린 기기에서 콜드 스타트 시간이 단축됩니다.
React Native 면접 준비가 되셨나요?
인터랙티브 시뮬레이터, flashcards, 기술 테스트로 연습하세요.
프로덕션 빌드에서 바이트코드 컴파일 검증하기
흔한 실수는 Hermes 바이트코드가 자동으로 배포된다고 가정하는 것입니다. 디버그 빌드에서는 빠른 반복을 위해 일반 JavaScript를 사용할 수 있어, 개발자가 프로덕션 환경까지 바이트코드 관련 문제를 인지하지 못할 수 있습니다. 검증을 위해서는 실제 번들 내용을 확인해야 합니다.
# Android: Check for Hermes bytecode in APK
unzip -l app-release.apk | grep -E "bundle$|hbc$"
# Expected: assets/index.android.bundle (should be HBC format)
# Verify file is actually bytecode, not plain JS
unzip -p app-release.apk assets/index.android.bundle | head -c 8 | xxd
# Hermes bytecode starts with magic bytes: c6 1f bc 03
# iOS: Check for bytecode in IPA
unzip -l App.ipa | grep -E "main.jsbundle"
# Extract and verify magic bytes same as Android번들이 바이트코드가 아닌 일반 JavaScript인 경우, 빌드 설정에서 Hermes가 비활성화되어 있거나 Metro 트랜스포머 오버라이드가 hermesc를 우회하고 있을 가능성이 있습니다. react-native.config.js를 확인하고 커스텀 트랜스포머가 바이트코드 생성을 방해하지 않는지 확인해야 합니다.
module.exports = {
// Do NOT set hermes_enabled: false
// Hermes is default in 0.84+
project: {
ios: {},
android: {},
},
// Custom assets configuration if needed
assets: ['./src/assets/fonts'],
};Hermes V1 관련 기술 면접 질문
시니어 React Native 포지션에서는 Hermes 관련 질문이 점점 증가하고 있습니다. 이러한 질문들은 앱 성능에 직접적인 영향을 미치는 JavaScript 엔진 계층에 대한 이해도를 평가합니다.
질문 1: Hermes 바이트코드 컴파일과 V8 JIT 컴파일의 차이점을 설명하십시오
Hermes는 AOT(Ahead-of-Time) 컴파일을 사용합니다. JavaScript는 개발 머신이나 CI 서버에서 빌드 프로세스 중에 바이트코드로 변환됩니다. 컴파일된 바이트코드는 앱 바이너리와 함께 배포됩니다. 런타임에 Hermes는 JavaScript 소스를 파싱하지 않고 바이트코드를 직접 실행합니다.
V8은 JIT(Just-in-Time) 컴파일을 사용합니다. JavaScript 소스가 앱과 함께 배포됩니다. 런타임에 V8은 소스를 파싱하고 바이트코드를 생성한 다음, 단계적 컴파일(Ignition 인터프리터 → TurboFan 최적화 컴파일러)을 통해 핫 함수를 점진적으로 최적화합니다.
트레이드오프: Hermes는 피크 실행 속도를 희생하고 일관된 시작 성능을 달성합니다. V8의 JIT는 결국 Hermes 바이트코드보다 핫 경로를 더 빠르게 실행할 수 있지만, 웜업 시간과 최적화 컴파일러를 위한 메모리가 필요합니다. 모바일 앱은 피크 처리량보다 빠른 시작에서 더 큰 이점을 얻습니다. 사용자는 인터랙티브 상태가 되기까지 3초 이상 걸리는 앱을 이탈하는 경향이 있습니다.
질문 2: Hades GC가 GenGC와 어떻게 다르며, 왜 변경이 필요했습니까?
GenGC는 싱글 스레드입니다. 모든 가비지 컬렉션 작업이 JavaScript 실행을 중단합니다. 마크 단계는 객체 그래프를 순회하고, 컴팩트 단계는 힙을 조각 모음합니다. 둘 다 메인 스레드에서 수행됩니다. 복잡한 앱에서 GC 일시 정지는 수백 밀리초에 달했습니다.
Hades는 대부분 동시성으로 동작합니다. 백그라운드 스레드가 JavaScript 실행 중에 마크 스윕 컬렉션을 수행합니다. 루트 마킹과 약한 참조 파이널라이제이션을 위해 짧은 스톱 더 월드 일시 정지가 남아 있지만, 일반적으로 10ms 미만입니다. 영 제너레이션은 여전히 복사 컬렉션(빠르지만 일시 정지 필요)을 사용하고, 올드 제너레이션은 동시성 마크 스윕을 사용합니다.
이 변경이 필요했던 이유는 모바일 UI 프레임워크가 60fps 애니메이션을 위해 16ms 프레임 예산을 요구하기 때문입니다. 200ms를 초과하는 GenGC 일시 정지는 눈에 보이는 버벅거림과 낮은 사용자 경험 평가를 초래했습니다.
질문 3: Hermes에서 프리테뉴어링이란 무엇이며 언제 조정해야 합니까?
프리테뉴어링은 첫 32MiB를 영 제너레이션 컬렉션을 건너뛰고 올드 제너레이션에 직접 할당합니다. React Native 초기화는 영 제너레이션 컬렉션의 이점을 받지 못하는 오래 살아남는 객체(내비게이션 상태, Redux 스토어, API 클라이언트)를 생성합니다. 프리테뉴어링은 시작 시 컬렉션에서 오탐을 방지합니다.
조정 시나리오: 비정상적으로 큰 초기화 할당(무거운 네이티브 모듈 설정, 큰 정적 데이터셋)이 있는 앱은 프리테뉴어 크기 증가로 이점을 얻을 수 있습니다. 최소 메모리 풋프린트에 최적화된 앱은 이를 줄일 수 있습니다. 실제로 32MiB 기본값은 대부분의 앱에서 잘 작동하며, 변경 전에 실제 기기 메트릭을 사용한 프로파일링이 선행되어야 합니다.
질문 4: Hermes 기반 React Native 앱에서 메모리 누수를 디버깅하는 방법은?
React Native 내장 성능 모니터를 사용하여 JS 힙 크기 추세를 관찰하는 것으로 시작합니다. 정상 사용 중에 힙이 증가하면 누수를 나타냅니다. Flipper의 Hermes 디버거를 사용하여 누수가 의심되는 시나리오 전후의 힙 스냅샷을 캡처합니다.
React Native에서 흔한 누수 패턴:
- 정리 함수에서 제거되지 않는 이벤트 리스너
- 오래 살아남는 콜백에서 컴포넌트 상태를 캡처하는 클로저
- 화면 언마운트 후에도 유지되는 내비게이션 리스너
- 언마운트 시 중지되지 않는 애니메이션 값
// Memory leak pattern - closure captures component scope
function LeakyComponent() {
const [data, setData] = useState(largeDataset);
useEffect(() => {
// This closure captures 'data' - if interval persists, so does data
const interval = setInterval(() => {
console.log(data.length); // Leak: data never GC'd while interval runs
}, 1000);
// Fix: clear interval on unmount
return () => clearInterval(interval);
}, [data]);
}질문 5: Hermes에서 네이티브 모듈을 사용할 때 스레딩 관련 고려 사항은?
Hades는 JavaScript 객체를 생성된 스레드가 아닌 백그라운드 GC 스레드에서 파괴합니다. 스레드 로컬 리소스(GPU 컨텍스트, 네이티브 핸들)를 유지하는 라이브러리는 정리 코드가 싱글 스레드 파괴를 가정하면 크래시할 수 있습니다.
주목할 만한 예시: React Native Skia는 스레드별로 GPU 컨텍스트를 관리합니다. UI 스레드에서 생성된 객체는 UI 스레드에서 파괴되어야 합니다. 라이브러리는 정리를 위한 올바른 스레드 어피니티를 보장하기 위해 특별한 참조 카운팅을 구현합니다.
커스텀 네이티브 모듈을 작성할 때, 소멸자 로직이 올바른 스레드에서 실행되거나 스레드 세이프한지 확인해야 합니다. 특정 스레드 어피니티가 필요한 정리에는 플랫폼별 스레드 디스패치(Android: Handler.post(), iOS: dispatch_async())를 사용하십시오.
성능 벤치마크: Hermes V1 vs 이전 버전
실제 측정을 통해 주요 메트릭 전반에 걸친 Hermes V1 개선 사항이 입증되었습니다:
| 메트릭 | Hermes Legacy | Hermes V1 | 개선 |
|---|---|---|---|
| 콜드 스타트 (TTI) | 2.8초 | 1.9초 | 32% 단축 |
| 웜 스타트 | 1.2초 | 0.8초 | 33% 단축 |
| JS 힙 크기 | 45MB | 38MB | 16% 감소 |
| GC 일시 정지 (p99) | 180ms | 12ms | 93% 감소 |
| 번들 크기 | 4.2MB | 3.1MB | 26% 감소 |
벤치마크는 Pixel 6a(Android)와 iPhone 12(iOS)에서 테스트된 중간 복잡도의 이커머스 앱 기준입니다. 결과는 번들 크기, 화면 수, 네이티브 모듈 사용량에 따라 달라집니다.
JSC에서 마이그레이션하는 팀의 경우 개선 효과가 더욱 극적입니다. 특히 메모리가 제한된 Android 기기에서 이전에 500ms를 초과했던 GC 일시 정지에서 두드러진 개선을 확인할 수 있습니다.
결론
- Hermes V1은 프리컴파일된 바이트코드를 배포하여 런타임 JavaScript 파싱을 제거하고 Time to Interactive를 25~50% 단축합니다
- Hades 동시성 가비지 컬렉터는 가비지 컬렉션 일시 정지를 수백 밀리초에서 p99 기준 12ms 미만으로 줄여 부드러운 60fps 애니메이션을 유지합니다
- 프리테뉴어링(기본 32MiB)은 초기화 객체를 올드 제너레이션에 직접 할당하여 시작을 최적화합니다
- 프로덕션 빌드가 일반 JavaScript가 아닌
.hbc바이트코드를 포함하는지 매직 바이트(c6 1f bc 03)를 확인하여 검증해야 합니다 - 지연 함수 컴파일로 초기 메모리 풋프린트가 감소합니다. 거의 사용되지 않는 기능의 컴파일을 지연시키도록 코드를 구조화해야 합니다
- 네이티브 모듈 작성자는 스레드 로컬 리소스를 관리할 때 백그라운드 스레드에서의 객체 파괴를 고려해야 합니다
- 기술 면접에서는 Hermes 내부에 대한 평가가 증가하고 있습니다: 바이트코드 vs JIT 트레이드오프, GC 아키텍처, 메모리 디버깅 워크플로우가 주요 주제입니다
연습을 시작하세요!
면접 시뮬레이터와 기술 테스트로 지식을 테스트하세요.
React Native 코드의 버그를 찾을 수 있나요
실제 코드 한 조각, 숨은 버그 하나, 하루 한 번. 계정 없이 바로 도전할 수 있습니다.

작성자
Anthony Fillion-MailletSharpSkill 창업자
10년 이상 풀스택 개발을 해왔습니다. SharpSkill을 운영하며 이곳에 게시되는 모든 내용에 책임을 집니다.
2026년 7월 27일 업데이트
태그
공유
관련 기사

Flutter vs React Native 성능 비교 2026: 벤치마크와 면접 질문
Flutter 3.38과 React Native 0.82의 성능을 철저히 비교합니다. Impeller 엔진, 새로운 아키텍처, 프레임 레이트 벤치마크, 메모리 사용량, 채용 면접에서 자주 나오는 질문들을 다룹니다.

React Native 0.86 완벽 가이드 2026: Android 15 엣지투엣지 지원과 DevTools 활용법
React Native 0.86의 Android 15 엣지투엣지 지원, DevTools 개선 사항, 면접 대비 질문을 상세히 다룹니다. 실용적인 코드 예제와 최신 베스트 프랙티스를 소개합니다.

React Native와 TypeScript 2026: 타입 안전한 아키텍처와 면접 질문
TypeScript로 타입 안전한 React Native 앱을 구축하는 방법을 다룹니다. Codegen, TurboModules, 0.87에서 필수화된 Strict TypeScript API, 아키텍처 패턴, 타입 안전 내비게이션, 툴체인 요구 사항, 면접 질문을 코드 예제와 함께 설명합니다.