메모리 관리 — 누수 탐지와 최적화
메모리 누수는 앱이 점점 느려지다가 결국 크래시하는 원인이 됩니다. 특히 모바일에서는 메모리 제한이 엄격합니다.
흔한 메모리 누수 패턴
1. 언마운트된 컴포넌트에서 상태 업데이트
// 나쁜 예: 컴포넌트 언마운트 후 setState 호출
function BadComponent() {
const [data, setData] = useState(null);
useEffect(() => {
fetchData().then((result) => {
setData(result); // 이미 언마운트되었을 수 있음!
});
}, []);
}
// 좋은 예: AbortController로 취소
function GoodComponent() {
const [data, setData] = useState(null);
useEffect(() => {
const controller = new AbortController();
fetch('/api/data', { signal: controller.signal })
.then((res) => res.json())
.then(setData)
.catch(() => {}); // abort 에러 무시
return () => controller.abort(); // 언마운트 시 요청 취소
}, []);
}
2. 이벤트 리스너 해제 누락
// 나쁜 예
useEffect(() => {
const subscription = AppState.addEventListener('change', handleChange);
// return으로 해제하지 않음!
}, []);
// 좋은 예
useEffect(() => {
const subscription = AppState.addEventListener('change', handleChange);
return () => subscription.remove(); // 클린업 필수
}, []);
3. 타이머 해제 누락
useEffect(() => {
const timer = setInterval(() => {
fetchNewData();
}, 5000);
return () => clearInterval(timer); // 반드시 해제
}, []);
4. 클로저에 의한 참조 유지
// 큰 데이터를 클로저가 참조하고 있으면 GC가 수거하지 못함
function ProcessScreen() {
const [largeData, setLargeData] = useState<LargeObject | null>(null);
const handleProcess = useCallback(() => {
// largeData를 클로저가 참조 → 메모리 유지
processData(largeData);
}, [largeData]);
// 화면 벗어날 때 큰 데이터 해제
useFocusEffect(
useCallback(() => {
return () => setLargeData(null);
}, [])
);
}
이미지 메모리 관리
// 큰 이미지는 메모리를 많이 차지함
// 4000x3000 RGBA = 약 48MB 메모리
// 해결: 적절한 크기로 리사이즈
<Image
source={{ uri: imageUrl }}
style={{ width: 200, height: 200 }}
resizeMethod="resize" // Android: 메모리에서 리사이즈
/>
// FlatList에서 이미지 목록
// removeClippedSubviews로 화면 밖 이미지 메모리 해제
<FlatList
data={images}
renderItem={renderImageItem}
removeClippedSubviews={true}
windowSize={3} // 작은 값으로 메모리 절약
/>
메모리 모니터링
// 개발 중 메모리 확인
// Xcode: Debug Navigator → Memory
// Android Studio: Profiler → Memory
// Flipper에서 메모리 스냅샷 촬영
// Heap 크기 변화를 시간순으로 추적
// React Native Performance Monitor
// 개발 메뉴 → "Show Perf Monitor"
// RAM 사용량 실시간 확인
최적화 전략
- useEffect 클린업을 항상 작성 하세요
- 큰 데이터는 화면 이탈 시 해제 하세요
- 이미지는 적절한 크기로 제공하세요
- FlatList의 windowSize를 줄여 렌더링 범위를 제한하세요
- ** 불필요한 전역 상태를 피하세요** — 화면 로컬 상태로 충분한 것은 로컬에 두세요
정리
- useEffect의 클린업 함수 가 메모리 누수 방지의 핵심입니다
- 이벤트 리스너, 타이머, 구독은 반드시 해제 하세요
- 큰 이미지는 서버에서 적절한 크기로 제공 하는 것이 최선입니다
- Xcode/Android Studio Profiler 로 메모리 사용량을 모니터링하세요
- 메모리 문제는 점진적으로 나타나므로 장시간 사용 테스트 가 중요합니다
댓글 로딩 중...