CPU, RAM, 저장 장치의 역할과 상호 작용
| 구성 요소 | 역할 |
|---|
| CPU (중앙처리장치) | 앱의 로직을 실행하고 연산을 처리하는 핵심. UI 렌더링, 사용자 입력 처리, 네트워킹 등 대부분의 실행 흐름 담당 |
| RAM (메모리) | 실행 중인 앱의 데이터(코드, 변수, 이미지 등)를 임시 저장. 빠르게 접근할 수 있어 CPU가 효율적으로 작업 가능 |
| 저장 장치 (Storage, SSD) | 앱, 사진, 파일 등 장기 보관용 저장소. 앱 설치 시 코드와 리소스가 저장되며, 실행 시 RAM으로 복사됨 |
상호작용 흐름 (앱 실행 시)
저장 장치
⬇️ (앱 실행 요청)
RAM
⬇️ (앱 실행 중)
CPU
RAM에서 코드, 데이터 가져와 실행
앱 실행 시 동작 순서
- 저장 장치에서 앱 바이너리와 리소스를 로드
- OS가 앱을 실행하라는 요청을 받으면
- 앱 번들을 저장 장치에서 RAM으로 복사함.
- RAM에 적재되면 CPU가 실행 시작
- main() 함수 또는 @UIApplicationMain 엔트리포인트부터 실행.
- 앱 로직, UI 그리기 등은 CPU가 처리하고
- 필요한 데이터는 RAM에 임시로 저장/불러오기 함.
- 앱 화면을 렌더링
- UIKit이나 SwiftUI가 View를 구성하고,
- Core Animation이 실제 화면에 렌더링 -> 사용자에게 보임
RAM이 부족할 때 iOS의 동작
iOS는 메모리가 제한된 환경이므로 다음과 같은 메모리 관리 정책을 가짐
iOS의 Low Memory Handling
- iOS가 먼저 백그라운드 앱을 종료
- LRU(Least Recently Used) 순으로 메모리 확보
- 실행 중인 앱에 경고 (didReceiveMemoryWarning) 발생
- UIKit에서 이 메서드를 통해 캐시, 이미지, 불필요한 뷰를 제거하도록 유도
- 앱이 메모리를 해제하지 않으면 강제 종료
- SIGKILL로 앱 크래시 발생 (사용자 알림x)
앱 개발 시 중요한 이유
- 불필요한 이미지 캐싱, 메모리 누수(ARC 미사용 등)는 앱 종료 유발
- 특히 스크롤뷰 내 대용량 이미지, AVPlayer, 비동기 작업 누수 등은 자주 원인됨
- Memory graph와 Instruments로 점검 필수
CPU 속도 vs RAM 용량 vs 저장 장치 속도 체감 속도 영향
| 요소 | 체감 속도 영향도 | 이유 |
|---|
| RAM 용량 | 🟨 중간 | 충분하면 앱 전환, 멀티태스킹이 빠름. 부족하면 자주 재시작됨 |
| 저장 장치 속도 (SSD) | 🟨 중간 | 앱 설치, 최초 실행, 큰 파일 읽기에 영향 |
| CPU 속도 | 🟩 가장 큼 ✅ | 애니메이션, 로직 처리, 뷰 렌더링 등 모든 실행 흐름의 중심이므로 가장 체감에 영향 |
ex)
- 이미지 필터 앱에서 필터 적용 속도 -> CPU
- 앱 전환 시 이전 상태 유지 여부 -> RAM
- 앱 처음 실행될 때 딜레이 -> 저장장치 + RAM
추가하면 좋은 포인트
- 앱이 백그라운드에서 사라지면 메모리가 해제되며, 다시 실행 시 cold start 발생
- iOS는 자체적으로 메모리 압박을 감지하고 proactive하게 앱 종료를 관리(watchdog)
- 성능 최적화 시 lazy load, image downsampling, 데이터 prefetching 기법을 사용
용어 정리
-
Cold Start
앱이 완전히 종료된 상태에서 다시 실행되는 것.
즉, 메모리에 아무것도 남아 있지 않은 상태에서 앱이 처음부터 다시 시작.
-
Warm Start
* 앱이 백그라운드에 남아있고, 메모리에 일부 상태가 유지된 상태에서 다시 포그라운드 전환
-
Memory Pressure
* 시스템이 RAM 부족을 감지하는 상황. 여러 앱이 실행되며 RAM이 가득 차면 발생.
-
Watchdog
iOS 내부의 감시 시스템. 앱이 특정 시간 내에 실행/반응하지 않거나
메모리를 너무 많이 쓰면 앱을 강제로 종료(SIGKILL) 시킴
lazy load, imagedownsampling, 데이터 prefetching 기법
Lazy Load
lazy var profileImage: UIImageView = {
let imageView = UIImageView()
imageView.image = UIImage(named: "placeholder")
return imageView
}()
- 필요할 때만 리소스 로딩
- ex) 이미지 뷰가 실제 화면에 나타날 때 이미지 불러옴
- 장점: 메모리 낭비 감소
- 주의점: 사용전에 반드시 초기화 해야함
Image Downsampling
let processor = DownsamplingImageProcessor(size: imageView.bounds.size)
imageView.kf.setImage(with: url, options: [.processor(processor)])
- 큰 이미지를 디스플레이 크기에 맞게 줄여서 로딩
- 특히 고해상도 이미지를 그대로 메모리에 올리면 OOM발생 위험
- ex) Kingfisher, SDWebImage
Prefetching
func tableView(_ tableView: UITableView, prefetchRowsAt indexPaths: [IndexPath]) {
// indexPaths에 해당하는 데이터를 미리 불러오기
}
- 아직 화면에 보이지 않는 데이터를 미리 로드하여 스크롤을 부드럽게 만듬
- UITableViewDataSourcePrefetching or UICollectionViewDataSourcePrefetching 활용
- 장점: 느린 네트워크에서도 부드러운 UX 제공
- 주의점: 너무 많은 prefetch는 오히려 메모리 부담 초래