# 개요
# iOS 메모리 WWDC 세션
memory footprint -> 프로그램이 실행되는 동안 사용하거나 참조하는 메인 메모리의 양
# 페이지
-> 페이지 당 사이즈는 일반적으로 16KB
-> 페이지 타입은 Clean & Dirty로 나눠짐
-> 앱 메모리 사용량은 페이지 수 X 페이지 크기
1KB 1000bytes -> int형 20000개면 80000bytes, 80KB니까 페이지는 6개
-> 50KB 이미지를 캐싱할 때 4페이지로 쪼개져서 메모리 매핑 진행됨
# 가상 메모리와 페이징에 대한 개념
iOS 메모리 뜯어보기 (opens new window)
- 프로그램 동작을 위한 메모리 영역은 운영체제에서 할당해준다.
- 물리적인 RAM 주소를 알려주는 것이 아닌 가상의 메모리 주소를 알려줌
- 가상 메모리 공간은 연속되지 않고 여러 군데 나뉘어 존재한다
- 페이징 방식이란 가상 메모리 공간을 일정 크기로 분할하여 각 공간을 물리적 메모리 공간에 매핑하는 방식을 말한다
- 가상 메모리 블록을 페이지라고 하고, 같은 크기의 메모리 블록을 프레임이라고 한다.
- 각 프로세스에는 페이지가 어떤 물리 주소에 매핑되어야 하는지의 정보를 저장하고 있는 페이지 테이블이 존재. 페이지 테이블에는 페이지 테이블 엔트리(PTE)들이 존재하며 각 PTE에는 프레임 번호와 함께 추가적인 상태 비트 저장
# 앱 사용량 (footprint)의 구성요소
-> Dirty
- 앱에서 사용된 메모리
- Array, NSCache, malloc, UIViews..
- 힙 할당, 객체들
- 디코딩 이미지 버퍼
- UIKit, CoreGraphics.. 프레임워크들
-> Compressed
- 액세스 되지 않은 페이지를 가져와서 압축 후 더 많은 공간을 만들어주는 공간
- iOS에서는 디스크 스왑을 제공하지 않는다. (하드 일부를 RAM처럼 사용하게 해주는 것)
- 메모리가 부족할때 당장 필요치 않은 데이터를 하드에 옮겨 사용
- 여러 페이지에 할당된 데이터가 있을때 액세스 빈도가 낮은 경우 자동으로 압축
-> Clean 구성 데이터
- 페이징 가능한 대상들
- memory mapped files (jpg 기타 등등)
- 프레임워크
# 메모리 경고?
didReceiveMemoryWarning()
-> 메모리 부족 현상이 발생한 경우 시스템에서 자동으로 호출되는 함수
-> 오버라이딩 하여 해당 함수 호출시 캐싱 정책을 디테일하게 만질 필요가 있을 수도 (캐싱 일시중단 or 백그라운드 작업제한)
override func didReceiveMemoryWarning() {
cache.removeAllObjects()
super.didReceiveMemoryWarning()
}
# 캐싱 주의점
- CPU 절약을 위해 캐싱을 사용하되, 너무 많이 사용하면 메모리를 모두 소진하여 문제 발생
- 컴프레서를 통해 액세스가 덜한 메모리를 잘 처리하기
# Memory Limit
- 기기마다 너무 다르다 (1GB ~ 4GB)
# 프로파일링
- VM Tracker
- Xcode Instruments -> Dirty & Compressed 메모리를 트래킹할 때 사용
- VM Memory trace
- 앱 가상메모리 시스템 성능 체크
- 캐시 히트 체크
- 기기 메모리 제한에 접근 -> EXC 리소스 예외 발생, 디버거 자동으로 시작
- memgraph 보여줌
- CLI 환경에서
.memgraph
파일 내보낸 뒤vmmap App.memgraph
로 읽으면 메모리 소비에 대한 분석을 요약해줌 - 더티 메모리, 스왑 & 컴프레싱 메모리 양에 대해 세부 정보 제공
- 더티와 스왑이 중요한데, 스왑 크기가 압축 이후 데이터가 아니라 압축 이전의 크기를 제공한다는 것
# Images in iOS
-> 2048 X 1536 픽셀의 이미지가 있을때, 파일 사이즈는 590KB이지만, 메모리에 로드될 때는 10MB이다. (픽셀당 4바이트)
-> 실제 파일사이즈와 메모리상에서 사용되는 이미지 객체 크기 차이가 크기 때문에.. iOS에서 이미지가 다뤄지는 과정을 알아야함
이미지는 세 단계에 거쳐 렌더링된다.
- Load -> 원본 파일데이터 로드 (590KB)
- Decode -> GPU가 읽을 수 있는 형태로 변환 (10MB, 압축 풀기), SRGB 포맷
- iOS에서는 풍부한 색 표현을 위해 와이드 포맷이라는 것을 사용함 (사용 안해도 됨)
- 더 작게 알파 8포맷 혹은 루미넌스 포맷 사용 가능 (일반적으로는 사용 X)
- 1바이트 ~ 8바이트까지 처리 가능하다는 것을 아는게 중요하다.
- 어떤 형식을 선택하느냐? UIGraphics ImageRenderer API를 사용하면 가장 적합한 그래픽 방식을 선택함.
UIBezierPath
로 원을 그릴때UIGraphicsBeginImageContextWithOptions
레거시 API를 사용하면 픽셀당 4바이트로 처리UIGraphicsImageRenderer
로 처리한 경우 자동으로 픽셀당 1바이트로 처리- 동일한 마스크 사용하면서
tintColor
만 사용하면 불필요한 메모리 사용량 줄일 수 있음
- Render -> 렌더링
이미지 리사이징
- UIImage는 리사이징 하는데에 비용이 많이든다.
- 내부 좌표 공간 변화로 인해 성능이 조금 떨어진다.
- 메모리 압축을 디코딩 과정도 포함되어서 성능에 추가비용 존재
ImageIO API
- 이미지 다운샘플링, 이미지
- 로우레벨 -> 파일 앱에서 이미지 가져올때 사용해보기
백그라운드
-> 노티피케이션 센터의 UIApplicationDidEnterBackground
사용, 앱 백그라운드 진입시 이미지 언로드
-> 노티피케이션 센터의 UIApplicationWillEnterForeground
사용, 앱 포어그라운드 진입시 이미지 로드