[WWDC 2018] iOS Memory Deep Dive (1/2)
WWDC 2018 iOS Memory Deep Dive 를 정리한 포스트입니다.
더 자세한 내용을 원하시면 위 링크를 참조하시길 바랍니다.
Virtual Memory?
Device마다 RAM의 크기는 다르며, 서로 다른 RAM 시스템을 통일된 Adress 시스템으로 추상화하는 기술을 Virtual Memory라고 합니다.
Virtual Memory 주소가 "Virtual"의 의미는 물리적 주소가 정렬할 필요가 없다는 것을 의미합니다.
앱의 모든 프로세스는 가상 메모리 공간을 확보하고 해당 공간의 모든 주소에 액세스 할 수 있습니다.
모든 가상 메모리 공간에는 동일한 주소 목록이 있다는 점을 고려해야 합니다.
한 프로세스에서 동일한 주소는 다른 프로세스에서 다른 물리적 주소이므로 다른 프로세스의 메모리 블록에 액세스할 수 없습니다.
모든 가상 메모리 공간은 가상 주소를 물리적 주소에 매핑합니다. 그리고 18엑사바이트를 가진 장치가 없기 때문에, 시스템은 제약에 직면할 수 있습니다.
OSX와 달리 iOS에는 백업 저장소가 없습니다. 즉, iOS는 메모리 데이터를 보관하기 위해 디스크를 사용하지 않기 때문에 시스템은 물리적 RAM 크기로만 제한됩니다.
Clean Dirty Pages
Virtual Memory는 공간을 페이지라고 불리는 청크로 나눕니다.
페이지는 어떤 종류의 데이터도 담을 수 있는 16KB 청크입니다.
Memory mapped files
50 KB 크기의 JPEG가 메모리에 매핑되면 실제로 4 페이지의 메모리에 매핑되거나 제공됩니다.
이제 네 번째 페이지는 실제로 완전히 채워지지 않았으므로 다른 용도로 사용할 수 있습니다.
Clean memory
디스크에서 로드할 수 있으며("Page out") 프레임워크, 실행 코드 및 읽기 전용 파일을 포함합니다.
Dirty memory
앱, 힙 할당, 싱글 톤, 글로벌 이니셜 라이저 및 스택으로 채워진 메모리입니다.
Compressed memory
iOS 7부터 도입되었습니다.
할당은 되었으나 액세스되지 않은 페이지를 압축하고 액세스시 페이지 압축 해제를 합니다.
액세스 전
액세스 후
사용 중인 메모리는 Dirty + Compressed memory입니다.
clean memory는 언제든지 복원할 수 있기 때문에 쉽게 무시할 수 있습니다.
Memory warnings
캐시 할 때 실제로 반복 작업을 수행하지 않고 CPU를 절약하려고 하지만
너무 많은 캐시를 사용하면 모든 메모리를 사용하게되므로 시스템에 문제가 발생할 수 있습니다.
따라서 Compressed memory와 Cache가 있다는 것을 기억해야 합니다.
Caching해야 할 것과 재 계산해야 할 것에 대한 균형을 잡는 것이 필요합니다.
Caching
Dictionary 보다 NSCache 를 사용하는 것을 권장합니다.
NSCache 는 제거(purgeable) 될 수 있기 때문입니다.
제거된 다면 Compressor 를 통해 memory 가 압축될 것입니다.
Typical app memory profile
클린 메모리는 실제로 계산되지 않습니다.
모든 앱에는 설치 공간 제한이 있습니다.
extenstion 은 메모리 제약이 많습니다.
extenstion이 메모리 한도를 초과하면 EXC_RESOURCE_EXCEPTION 이 발생합니다.
Tools for Profiling Footprint
Xcode memory gauge
디버그 탐색기에 바로 표시되며 앱의 메모리 공간을 빠르게 볼 수있는 좋은 방법입니다.
Instruments - VM Tracker
VM Tracker 는 3가지 그래프를 제공합니다.
- Dirty Size
- Swapped Size(Compressed memory)
- Resident Size
Instruments — Virtual Memory Trace
가상 메모리 시스템 프로파일을 제공하고 VM의 Page cache hits 및 Page zero fills와 같은 항목을 표시합니다.
Xcode Memory Debugger
Xcode 용 메모리 디버거는 Xcode 8로 제공되었으며 객체 종속성,주기 및 누수를 추적하는 데 도움이 됩니다.
Xcode Memory Debugger
Memory Debugger 화면에서 Memory Graph 파일을 내보낼 수 있습니다.
vmmap
내보낸 memory graph 파일을 명령어로 실행 할 수 있습니다.
vmmap --summary App.memgraph
위 명령어를 실행하면 Virtual Size, Resident Size 를 표시합니다.
Virtual Size: 앱이 원하는 모든 메모리입니다.
Resident Size: 실제 메모리에 실제로로드 된 메모리입니다.
resident memory = dirty memory + clean memory that loaded in physical memory
Dirty Size 도 표시합니다.
Swapped Size (Compressed Size) 를 표시합니다.
중요한 점 중 하나는 Swap 크기가 Compressed 데이터가 아니라 미리 압축 된 데이터 크기를 제공한다는 것입니다.
vmmap and AWK
예) 다른 날 VM 트래커에서 내 앱을 프로파일 링하는 중에 더티 메모리 양이 증가하는 것을 보았습니다.
그래서 Memgraph를 가져 와서이 더러운 데이터에 기여하는 프레임 워크 또는 라이브러리가 무엇인지 알고 싶습니다.
pages 플래그는 원시 바이트 대신 페이지 수를 인쇄 함을 의미합니다.
dylib을 검색하는 grep으로 파이프 했으므로 여기에 동적 라이브러리가 필요합니다.
그리고 마지막으로, 나는 그것을 더 간단한 간단한 awk 스크립트로 파이프하여 더티 열을 요약 한 다음 마지막에 더티 페이지 수로 인쇄합니다.
vmmap --pages app.memgraph | grep '.dylib' | awk '{ sum += $6 } END { print "Total Dirty Pages: " s
Leaks
런타임시 루팅되지 않은 힙의 오브젝트를 추적합니다.
따라서 Leak 물체가 보이면 절대 사용할 수없는 Dirty memory입니다.
3개의 객체가 있으며 모두 서로에 대한 강력한 참조하고 있습니다.
Retain Cycle을 만듭니다.
프로세스에서 malloc 스택 로깅이 활성화 된 경우 루트 노드에 대한 역 추적도 제공합니다.
Heap
힙 도구는 프로세스 힙의 객체 할당에 대한 모든 종류의 정보를 제공합니다.
heap --sortBySize App.memgraph
heap App.memgraph -addresses all | <classes-pattern>
NSConcreateData가 어디에서 왔는지 알아내기 위해선
먼저 NSConcreteData 객체 중 하나의 주소를 가져와야 합니다.
Enabling malloc stack logging
활성화되면 시스템은 각 할당에 대한 역 추적을 기록합니다.
malloc_history
malloc_history <memgraph> <address>
흥미롭게도 여기 NoirFilter의 apply 메소드가 거대한 NS 데이터를 생성하는 것처럼 보입니다.
Which tool to pick?
메모리 문제에 직면했을 때 어떤 도구를 선택합니까? 이것에 대해 생각할 수있는 3 가지 방법이 있습니다.
참조:
https://medium.com/better-programming/reducing-your-apps-memory-footprint-b7afcb9f3749
https://medium.com/better-programming/ios-advanced-memory-debugging-to-the-masses-24d25852a91c
https://developer.apple.com/videos/play/wwdc2018/416
https://hcn1519.github.io/articles/2018-09/wwdc2018session416