- WWDC 18 의 iOS Memory Deep Dive 세션을 정리
iOS 의 앱이 사용하는 메모리
- 시스템에서 제공하는 메모리 페이지는 Heap 에 여러 객체를 저장 할 수 있음
( 이미지의 1, 2 페이지 )
- 일부 객체는 여러개의 페이지에 걸쳐 있을 수도 있음
( 이미지의 3, 4 페이지 )
- 일반적으로 페이지의 크기는 16KB
Clean
or Drity
- 메모리 사용량 = 페이지 수 * 페이지 사이즈
- 예를 들어, 20,000개의 Int 배열을 할당하면 시스템에서는 6개의 페이지를 제공
- 첫 할당 시, Clean Page 로 제공 ( 푸른색으로 표시 )
- 이때, 데이터 버퍼에 Write 가 된다면 해당 페이지는 Dirty Page 가 됨 ( 붉은색으로 표시 )
- 파일은 디스크에 존재하지만, 메모리에 로드가 됨
- 읽기 전용 파일의 경우 항상 Clean Page ( Write 되지 않으니..! )
- 커널은 디스크에서 RAM 으로 들어오고 나갈 때 관리
- 아래 예시를 통해 확인
- 50KB 의 JPEG 이미지가 있다면, 이는 4개의 페이지에 매핑 됨
- 이때, 4번째 페이지는 아직 공간이 남아있기에 다른 데이터가 남아있는 공간을 차지할 수 있음
- 3개의 페이지는 제거 가능한 페이지 ( 다른 용도에 사용이 될 수 없는 메모리 페이지 -> 메모리가 부족하다면 시스템이 지울 수 있다는 의미 )
- 일반적으로 앱에서 Memory Profile 에는 Dirty, Compressed, Clean 이라는 메모리 세그먼트가 존재
- Clean Memory 는 페이지 기록 (Out) 될 수 있는 데이터
- 기록이 아직 되지 않고 있는 디스크의 데이터와 동일
- 이미지, 데이터, 모델, 프레임워크 (
__DATA_CONST
) 등등
- 앱에 의해 Write 된 메모리
- Heap 의 메모리 할당, Array, String, Cache, 프레임워크(
__DATA
, __DATA_DIRTY
) 등등
- Decode 된 이미지 버퍼
- iOS 는 디스크 스왑 방식을 따로 갖고 있지 않음 ( *디스크 스왑 : RAM 이 가득차면, 디스크 공간을 교환하여 사용 )
Memory Compressor
를 사용 ( iOS 7 도입 )
( *Memory Compressor : 아직 엑세스 되지 않은 페이지를 압축하여, 공간을 많이 사용하지 않도록 함. 메모리를 엑세스 할 때 압축 해제 )
- 아래 이미지 두개는 Dictionary 를 압축 / 해제 했을 때의 모습
- 항상 앱의 문제는 아님
- 메모리 자체가 부족할 수도 있고, 전화나 메세지 등 사용하면서 warning 이 나올 수도 있음
didReceiveMemoryWarning()
메서드를 사용하여, warning 이 트리거 되었을 때, 모든 캐시를 지우는 것이 좋을까?
그렇지 않음
- Memory Compressor 는 압축된 내용에 따라서 실제로 이전보다 더 많은 메모리를 사용할 수도 있음..
따라서 메모리 warning 이 발생했을 때 캐싱을 수행하지 않거나, 일부 백그라운드 작업을 제한하는 것과 같은 방법을 권장
- 아래 이미지 두개를 예시로 보면, Memory Compressor 에 의해 압축이 해제된 Dictionary 를 캐시를 지움으로 인해 다시 압축을 하게 되는 작업이 더 큰 비용을 지불 할 수도 있다는 것
- 캐싱은 CPU가 반복 작업을 하지 않도록 하려고 하는 것
- 너무 많은 캐싱을 하면 모든 메모리를 사용하게 되어 시스템에 문제가 발생할 수 있음
- 캐시와 Memory Compressor 사이에 균형을 맞추는 것이 중요
- 캐시는
NSCache
를 사용하면, 여러 쓰레드에서 동시 접근해도 안전 ( thread safe )
- 메모리에 저장된 데이터는 항상 제거 가능 ( purgeable )
- NSDictionary 보다 NSCache 사용 권장
- Clean Pages 는 실제로 계산되지 않음
- 모든 앱에는 Footprint limits ( 공간 제한 ) 이 있음
- 기기마다 제한이 변경 됨
- 익스텐션은 공간이 더 적음
- 초과시, Exception 발생 (
EXC_RESOURCE_EXCEPTION
)