본문 바로가기
강의 정리

WWDC 2018: iOS Memory Deep Dive(메모리 프로파일링)에 관하여

by iOS 개린이 2023. 6. 19.

Memory Footprint

 

메모리는 'Page' 단위로 관리된다. 페이지는 일반적으로 16K 크기를 가지며, 한 페이지에는 여러 개의 객체가 위치할 수도 있고, 큰 객체가 여러 페이지에 걸쳐 위치할 수도 있다.

 

시스템이 앱에 메모리 페이지를 할당하고, 아직 변경되지 않았다면, 그 페이지는 'clean' 상태이다.

하지만 앱이 페이지에 데이터를 쓰면(변경), 그 페이지는 'dirty' 상태가 된다. 

앱의 메모리 사용량은 이러한 페이지들의 총 크기로 측정된다.

 

위 사진에서 20,000 개의 정수를 담는 배열을 할당하면, 시스템은 이를 위해 여러 개의 페이지를 할당한다.

그리고 배열의 처음과 끝에 있는 정수를 변경하면, 해당 정수가 위치한 페이지는 'dirty' 상태가 되고,

그 사이에 있는 페이지들은 아직 변경되지 않았기 때문에 'clean' 상태를 유지한다.

 

Memory mapped files

-이는 디스크에 있는 파일이 메모리에 로드된 상태를 의미한다. 이 방법을 통해 앱은 파일을 메모리의 일부처럼 직접 접근할 수 있다. 'read-only(읽기전용)' 파일은 항상 'clean' 페이지로 유지된다. 커널은 이러한 파일들이 디스크와 RAM 사이에서 언제 로드되고 제거될지를 관리한다. JPEG 이미지 파일은 이러한 'Memory mapped file' 의 좋은 예시다.

 

 

50KB 크기의 JPEG 이미지가 메모리에 매핑되면, 이는 대략 4개의 메모리 페이지에 매핑된다. 하지만 네 번째 페이지는 완전히 차지 않기 때문에, 이 페이지의 나머지 부분은 다른 용도로 사용될 수 있다.

 

Typical app memory profile

 

일반적인 앱에서 설치 공간과 프로필은 다음과 같이 구성되어 있다. 이 것들을 분해해보자.

 

1. Clean Memory

이는 앱에 의해 아직 변경되지 않은 메모리를 말한다. 메모리에 매핑된 파일(이미지, 데이터 블롭 등)이 이에 해당한다.

또한, 각 프레임워크에는 'DATA CONST' 섹션이 있으며, 이는 일반적으로 'Clean' 상태를 유지한다. 하지만 런타임에 변경을 가하면(메소드 스위즐링 사용 등), 이 섹션은 'dirty' 상태가 될 수 있다. 

 

*메소드 스위즐링은 옵젝씨나 스위프트에서 사용하는 기법으로, 런타임에 메소드의 구현을 바꾸는 것을 말한다.

이 기법을 사용하면 'DATA CONST' 섹션에 저장된 원래의 메소드 구현을 변경할 수 있기 때문에, 이 섹션을 'Dirty' 상태로 만들 수 있음.* 

 

2. Dirty memory

이는 앱에 의해 변경된 메모리를 말한다. 객체, 문자열, 배열 등이 여기에 해당된다. 디코딩된 이미지 버퍼도 'Dirty' 메모리에 포함될 수 있다. 또한 프레임워크에는 'DATA' 섹션과 'DATA DIRTY' 섹션이 있으며, 항상 'Dirty' 상태의 메모리로 간주된다.

 

*앱이 동작하면서 데이터를 생성, 수정 등의 작업을 하는데 이렇게 변경된 메모리를 Dirty 메모리라고 한다.

이 변경된 메모리는 원래 데이터로 돌아갈 수 없기 때문에 시스템이 이를 재사용하려면 다시 초기화해야 한다.

Dirty 메모리는 앱의 성능과 안정성에 중요한 영향을 미친다. 이 메모리가 많아지면, 앱의 메모리 사용량이 늘어난다.

따라서 사용량을 최적화하는 것이 중요함.*

 

Frameworks

앱이 실행되는 동안 프레임워크를 사용하면서 메모리를 사용하게 된다.

여기서 일부 데이터가 'Dirty' 메모리가 될 수 있는데, 이것은 프레임워크를 연결하는 과정에서 필요한 부분이기 때문이다.

하지만 자신이 유지하는 프레임워크의 경우, 싱글턴 패턴이나, 'global initializers' 를 사용하면 'Dirty' 메모리 사용량을 줄일 수 있다. 싱글턴 객체는 한번 생성되면 항상 메모리에 올라와 있으며, 'global initializers' 는 프레임워크가 연결되거나 클래스가 로드될 때 실행된다.

 

 

3. Compressed memory

iOS 시스템에서 메모리 관리를 개선하기 위해 사용하는 특징 중 하나이다.

iOS 7 부터 도입된 기능으로, iOS에 디스크 스왑시스템이 없기 때문에 이를 대신하여 'memory compressor'를 사용한다.

 

'memory compressor' 는 오랫동안 사용되지 않은 메모리 페이지를 압축하여 메모리 사용량을 줄이는 방법이다.

압축된 메모리 페이지는 원래 데이터를 그대로 유지하면서, 더 적은 양의 메모리를 사용한다. 이렇게 하면 다른 부분에서 메모리가 필요할 때, 추가로 확보할 수 있는 공간을 만들어낸다.

앱이 압축된 메모리에 다시 접근하려고 하면, 다시 페이지를 압축 해제하여 원래의 크기로 복원한다.

 

예를 들어, 캐싱에 사용하는 'Dictionary' 가 3개의 페이지 메모리를 사용하고 있다고 가정해보자.

해당 'Dictionary' 에 오랫동안 접근하지 않았고, 시스템이 메모리 공간이 필요하다면, 시스템은 이 것을 압축하여 한 페이지의 메모리로 줄일 수 있다. 이렇게 하면 두 페이지의 메모리를 추가로 확보할 수 있다.

 

압축 전

https://hucet.tistory.com/38

압축 후

 

 

Memory warnings

주로 '메모리 경고'는 앱이 너무 많은 메모리를 사용하고 있어 시스템이 메모리 부족 상태에 처했을 때, 발생한다.

그러나 항상 앱이 과도하게 메모리를 사용하고 있을 경우에만, '메모리 경고' 가 나타나지는 않는다.

 

'메모리 경고'가 발생했을 때, 모든 메모리를 강제로 해제하는 것은 실제로는 메모리 사용량을 늘릴 수 있다.

이것은 iOS의 메모리 압축 기능 때문인데, 압축 해제 과정에서 발생한다.

예를 들어 압축된 데이터를 다시 압축 해제하면서 추가적인 메모리가 필요하기 때문이다.

따라서, 앱이 '메모리 경고' 를 받았을 때, 잠시 캐싱을 중단하거나, 백그라운드 작업을 제한하는 등의 전략을 사용하는 것이 더 효과적일 수 있다.

 

override func didReceiveMemoryWarning() { 
    cache.removeAllObjects()
    super.didReceiveMemoryWarning() 
}

 

이 코드는 앱이 메모리 경고를 받으면, 캐시에서 모든 객체를 제거한다. 

하지만 압축된 메모리 페이지가 압축 해제되면서 실제로 더 많은 메모리를 사용할 수 있다.

따라서 '메모리 경고' 를 처리하는 방식에 따라서 오히려 메모리 사용량을 증가시키는 결과를 가지고 올 수 있음을 인지해야 한다.

 

 

Caching

캐싱은 CPU가 반복적인 작업을 수행하는 것을 방지하기 위해 사용된다.

그러나 너무 많은 데이터를 캐시하면 전체 메모리를 다 사용하게 되고, 시스템에 문제가 발생할 수 있다.

따라서, 캐시해야 할 데이터와 다시 계산해야 할 데이터 사이의 적절한 균형을 맞추는 것이 중요하다.

 

이것을 위한 방법으로 'memory compressor' 와 'NSCache' 가 있다.

'memory compressor'는 앞서 설명했듯이 액세스되지 않는 메모리 페이지를 압축하여 메모리를 절약하는 역할을 한다.

 

NSCache는 'Thread-Safe' 방식으로 캐시된 객체를 저장하는 데 사용할 수 있다.

이는 딕셔너리에 비해 메모리 관리 측면에서 이점이 있다.

NSCache가 메모리를 할당하는 방식 때문에, NSCache의 메모리가 'purgeable(필요에 따라 시스템에 의해 해제될 수 있는)' 상태가 된다. 따라서 메모리가 제한적인 환경에서는 NSCache를 사용하는 것이 더 효과적일 수 있다.

 

 

다시 Typical app memory profile 로 돌아가서.

 

메모리 샤용량은 'Dirty', 'Compressed' 메모리로 측정이 된다.

'Clean' 메모리는 실제 앱의 메모리 사용량에 포함되지 않는다.

 

모든 앱에는 메모리 사용량의 한계가 있다. 이 한계는 앱에 따라 다르며, 사용하는 장치에 따라서도 변한다.

예를 들어, 1GB 메모리의 장치에서는 4GB 메모리의 장치보다 더 적은 메모리를 사용할 수 있다.

 

익스텐션은 앱의 확장 기능을 제공한다.

하지만 앱 본체보다 훨씬 작은 메모리 사용량을 가지기 때문에 더욱 주의 깊에 메모리를 관리해야 한다.

 

앱의 메모리 사용량이 한계를 초과하면, 'EXC_RESOURCER_EXCEPTION' 이 발생한다. 

이 exception은 앱이 할당받은 메모리 리소스를 초과하여 사용하려 할 때, 시스템에 의해 발생되는 것이다.

 

 

Tools for Profiling Footprint

 

Xcode의 디버그 네비게이터에 표시되는 메모리 게이지는 앱의 메모리 사용량을 빠르게 확인할 수 있는 좋은 방법이다.

 

Instruments

앱이 더 많은 메모리를 사용하고 있다는 것을 발견하면, 다음으로 사용해야 할 도구는 Instruments다.

이 도구는 앱의 메모리 사용량을 조사하는 여러 방법을 제공한다.

 

우리는 이미 'Allocations'와 'Leaks' 에 대해 익숙하다.

'Allocations' 는 앱이 힙에 할당하는 메모리를 프로파일링하고,

'Leaks' 는 프로세스에서 메모리 누수를 시간의 경과함에 따라 확인한다.

하지만 'VM Tracker'와 'Virtual memory trace'에 대해서는 잘 모를 수도 있다.

 

 

VM Tracker

VM Tracker는 iOS의 주요 메모리 분류 중 'Dirty', 'Compressed' 메모리의 프로파일링을 제공한다.

이 도구는 'Dirty' 메모리와 'Swap(iOS에서 Compressed 메모리를 의미함.)' 메모리에 대해 분리된 트랙을 제공하고, resident size(실제로 메모리에 올라와 있는 크기)에 대한 정보를 제공한다.

이 도구는 앱의 'Dirty' 메모리 크기를 조사하는데 매우 유용하다.

 

 

VM Memory Trace

VM Memory Trace는 앱과 관련하여 가상 메모리 시스템의 성능을 깊게 보여준다.

여기서 'by operation' 탭은 가상 메모리 시스템 프로파일을 제공하고, 'page cache hits'와 'page zero fills' 등을 보여준다.

 

'page cache hits'

페이지 캐시는 최근에 사용된 페이지의 복사본을 빠르게 접근할 수 있도록 메모리에 보관한다. 메모리에 대한 요청이 페이지 캐시에서 처리될 수 있을 때 'page cache hit' 가 발생하며, 이는 메모리에 대한 접근이 매우 빠르게 이루어짐을 의미한다.

즉, 요청된 데이터가 이미 메모리 상에 존재하므로 디스크를 거치지 않고 바로 데이터를 가져온다.

 

'page zero fills'

반면에 메모리 요청이 페이지 캐시에서 처리되지 않을 때, 'page zero fills' 가 발생한다. 

이 경우에는 디스크에서 직접 데이터를 읽어와야 하며, 상대적으로 느린 연산이다.

 

*VM(Virtual Memory)란?

가상 메모리는 컴퓨터 시스템의 메모리 관리 방식 중 하나로, 실제 물리적 메모리(RAM)의 크기를 초과하는 프로그램을 실행할 수 있게 해준다. 가상 메모리는 물리적 메모리를 '페이지' 라는 단위로 나누고, 이를 디스크의 '페이지 파일' 에 대응시키는 방식으로 작동한다.

 

RAM은 컴퓨터 시스템에 설치된 메모리 칩으로, 한정된 크기를 가지고 있다.

예를 들어, 컴퓨터에 8GB의 RAM이 설치되어 있다면, 이는 물리적인 메모리의 크기이다.

근데 가상 메모리는 물리적 메모리와 하드 디스크 공간의 일부를 결합하여 사용하기 때문에 RAM의 크기를 초과하는 프로그램을 실행할 수 있게 해주는 것이다.

 

어떤 프로그램이 실행되면서 필요한 메모리가 총 10GB라고 하자.

RAM은 8GB밖에 되지 않기 때문에, 운영 체제는 필요한 추가 데이터를 하드 디스크의 특정 영역에 저장한다.

이 영역을 '스왑 공간' 또는 '페이징 파일' 이라고 한다.

운영 체제는 RAM과 하드 디스크의 '스왑 공간' 사이에서 데이터를 주고받으면서 프로그램이 더 많은 메모리를 사용하는 것처럼 작동하게 해준다.

 

 

Xcode Debugger - memory resource exceptions

아까 얘기했듯이, 앱이 메모리 사용량의 한계에 도달하면 'EXC_RESOURCER_EXCEPTION' 가 발생한다.

Xcode 10에서 앱을 실행하면 Xcode는 이 exception을 잡아주면서, 앱을 일시 중지시킨다.

이를 통해 메모리 디버거를 시작하고, 해당 지점에서 조사를 시작할 수 있도록 한다.

 

Memory Debugger

Xcode 8부터 사용 가능하며, 개발자가 'Object dependencies', '순환참조', 그리고 메모리 누수를 추적하도록 도와주는 도구이다.

 

Memgraph 사용방법

Xcode의 메모리 디버거는 앱의 메모리 사용 정보를 저장하기 위해 'Memgraph' 라는 파일 형식을 사용한다.

Memgraph 를 사용하면 앱의 메모리 릭, 불필요한 메모리 사용, 가상 메모리 사용 등을 식별하고 문제를 해결하는데 도움이 된다. 또한 'command-line tool' 과 함께 사용하면 더욱 효과적인 메모리 분석이 가능하다.

 

세션을 보면 나와있는데, 

먼저 Memgraph 파일은 Xcode에서 간단히 내보낼 수 있다. 'export memgraph' 버튼을 클릭하고, 파일을 저장하면 된다.

이후 Memgraph 파일을 'command-line tool' 의 대상 인자로 전달하여 사용할 수 있다.

 

 

따라서 Xcode 10에서 앱을 실행하다가 'memory resource exception' 이 발생하면, Memgraph를 캡처하고 문제를 더 자세하게 조사해야 한다. 이를 통해 어떤 부분에서 메모리 사용량이 과도하게 늘어나는지 파악하고, 필요한 최적화를 실시할 수 있다.

 

 

VM Map('Memgraph'와 함께 사용할 'command-line tool')

 

이 도구는 프로세스에 할당된 가상 메모리 영역을 출력함으로써 앱의 메모리 사용량에 대한 고수준의 분석을 제공한다.

즉, 프로세스에 할당된 각 가상 메모리 영역의 크기, 속성, 상태에 대한 자세한 정보를 제공한다.

 

'summary flag' 를 사용하면, 각 영역의 메모리 크기, 'Dirty' 메모리의 양, 그리고 'Swapped(iOS에서 'Compress') 메모리의 양에 대한 상세 정보를 알려준다.

여기서 중요한 것은 'Dirty' 메모리와 'Swapped' 메모리가 앱의 전체 메모리 사용량에 미치는 영향이다. 또한, 'Swapped' 사이즈는 데이터가 압출된 후가 아닌 압축 전의 데이터 크기를 나타낸다.

 

 

만약 더 많은 정보를 얻고 싶다면,  'summary flag'를 제외하고, Memgraph에 대해 vmmap을 실행할 수 있다.

그러면 모든 영역의 내용이 출력된다. 예를 들어, 앱의 실행 코드인 프로그램의 텍스트나 쓰기가 불가능한 영역(데이터 섹션)을 출력한다. 프로세스의 힙도 포함된다.

 

이 도구들은 'standard comman-line utilities' 와 함께 잘 작동하기 때문에 유용하다.

 

vmmap and AWK

 

우리가 VM Tracker 에서 자신의 앱을 프로파일링하던 중 'Dirty' 메모리가 증가하는 것을 발견했다고 가정하자.

이 때, 'Dirty data' 에 기여하고 있는 것은 앱이 연결된 프레임워크일까? 라이브러리일까?

이것을 확인하기 위해 'Memgraph' 를 캡쳐하고, 이를 분석하기로 했다.

 

'vmmap -pages PlanetPics.memgraph' 

이 코드를 사용하면 해당 'Memgraph' 파일의 정보를 페이지 단위로 출력한다.

이 출력 내용은 앱의 메모리 사용에 대한 상세한 정보를 제공한다.

 

'grep .dylib'

이 코드를 통해 출력 내용 중에서 동적 라이브러리(확장자가 .dylib인 파일)를 찾는다.

이렇게 하면 앱이 연결된 각 라이브러리의 메모리 사용량을 확인할 수 있게 된다.

 

awk '{ sum += $6 } END { print "Total Dirty Pages: " sum}'

이 코드를 통해 동적 라이브러리에 의해 사용되는 'Dirty pages'의 총합을 계산하고 출력한다.

이렇게 하면 각 동적 라이브러리가 얼마나 많은 'Dirty pages' 를 사용하고 있는지 파악할 수 있다.

 

이러한 방법은 개발자가 디버깅 워크플로우를 구성함으로써, 특정 메모리 문제의 원인을 찾아낼 수 있다.

 

 

Leaks

 

실행중인 앱의 힙 메모리에서 참조되지 않는 객체를 추적하는 유틸리티이다.

이런 객체들은 '누수된 객체' 로 간주되며, 메모리가 누수되면 해당 메모리는 더 이상 해제할 수 없기 때문에 'Dirty' 메모리에 속하게 된다.

 

메모리 디버거의 leak

 

세 개의 객체가 모두 서로를 강하게 참조하여, 순환 참조를 만드는 경우이다.

이는 객체들이 서로를 참조하고 있어서 가비지 컬렉터나 ARC에 의해 메모리에서 제거되지 않는 상황을 말한다.

 

leak tool 에서의 leak

이것은 누수된 객체뿐만 아니라 그 객체들이 속한 순환 참조도 보여준다.

더불어 만약 'malloc stack logging(메모리 할당 스택 로깅)' 이 프로세스에서 활성화되어 있다면, 루트 노드에 대한 백트레이스(함수 호출의 역추적 정보)까지 제공해준다.

이 정보를 통해 개발자들은 메모리 누수의 원인을 찾아 해결하는데 도움을 받을 수 있다.

 

 

Heap

 

프로세스 힙 내의 객체 할당에 대한 여러가지 정보를 제공하는 도구이다.

이 도구는 매우 큰 할당 또는 동일한 종류의 객체가 많이 있는 경우를 추적하는데 도움이 된다.

 

Heap App.memgraph

 

Xcode가 'memory resource exception' 을 발견했을 때, 찍은 'memgraph' 가 있고, 이를 사용하여 힙을 조사하고자 한다. 그래서 'memgraph' 를 'heap'에 전달하였고, 이 도구는 각 객체의 클래스 이름, 그 객체의 수, 그리고 그 객체들의 평균 크기와 해당 클래스의 객체 전체 크기에 대한 정보를 제공한다. 

 

Heap --soryBySize App.memgraph

위의 예시에서도 볼 수 있듯이 Heap이 'count' 를 기준으로 정렬하고 있다.

하지만 우리가 보고 싶어하는 것은 가장 많은 수가 아닌 가장 큰 객체이다.

그래서 'sortBySize' 플래그를 heap 에 전달하면, 이 도구는 크기를 기준으로 정렬하게 된다.

 

우리는 이제 거대한 'NSConcreteData' 객체들을 확인할 수 있다. 

이 출력과 'memgraph'를 버그 리포트에 첨부해야겠지만, 이것만으로는 충분하지 않다.

우리는 이 객체들이 어디에서 비롯된 것인지 파악해야 한다.

 

먼저 'NSConcreteData' 객체들 중 하나의 주소를 얻어야 한다.

'heap'에 'addressed' 플래그를 전달하고 클래스 이름을 넣으면, 그 클래스의 각 인스턴스에 대한 주소가 제공된다.

그리고 이 주소를 통해 이것이 어디에서 비롯된 것인지 찾아볼 수 있다.

이 정보를 통해 어떤 부분이 많은 메모리를 차지하고 있는지, 그리고 그 원인이 무엇인지 파악할 수 있다.

 

 

malloc stack logging

 

이 기능을 활성화하면, 시스템은 각 할당에 대한 백트레이스를 기록한다.

이 로그는 'Memgraph' 를 기록할 때 캡쳐되며, 도구들의 기존 출력을 주석 처리하는데 사용돈다.

 

'Memgraph' 와 함께 사용하려는 경우, 'live allocations' 옵션을 사용하는 것이 좋다.

 

*백트레이스란

프로그램이 실행되는 동안 함수 호출의 추적을 나타낸다.

프로그램이 오류를 발생시키거나 예외 상황이 발생했을 때, 백트레이스는 프로그램의 실행 경로를 추적하여 어떤 함수 호출이 문제를 일으켰는지 파악하는데 도움을 준다. 

즉, 프로그램이 실행 경로를 추적하여 어떤 함수 호출들이 이루어져 현재 상태에 도달했는지 보여주는 지도와 같다.

 

따라서 'malloc stack logging' 을 활성화하면, 각 메모리 할당에 대한 백트레이스가 기록된다.

즉, 어떤 함수 호출이 메모리를 할당했는지, 그리고 그 메모리 할당이 프로그램의 어떤 실행 결로를 거쳐 이루어졌는지를 파악할 수 있게해준다. 이를 통해 비효율적인 메모리 사용이나 누수를 찾아내는데 유용하다.

 

 

malloc_history

 

위 명령 코드를 사용해 'Memgraph' 파일과 메모리 내 특정 인스턴스의 주소를 입력한다.

만약 해당 인스턴스에 대한 백트레이스가 캡쳐되었다면, 이 툴은 해당 정보를 제공할 것이다.

이를 통해 해당 메모리 주소에 할당된 객체가 어떤 경로로 생성되었는지를 파악할 수 있다.

 

malloc_history <memgraph> <address>

 

주어진 'NSConcreteData' 객체에 대한 주소를 'malloc history' 툴에 전달하여 어디서 그 객체가 생성되었는지를 백트레이스를 통해 확인했다.

 

백트레이스 결과, 'noirfilter' 의 'apply' 메서드가 거대한 'NSData' 를 생성하고 있음을 알 수 있었다.

이로서 해당 메서드가 메모리 사용에 문제를 일으키는 원인이라는 것을 확인하게 되었다.

 

따라서 이 정보와 함께 'Memgraph' 파일을 버그 리포트에 첨부하여 다른 개발자나 팀원이 해당 문제를 살펴볼 수 있도록 해야한다. 그리고 문제의 원인이 되는 코드를 찾아서 수정하게 될 것이다.

 

 

Which tool to pick?

 

메모리 문제에 직면했을 때, 어떤 도구를 선택할 지에 대해 고민한다면, 세 가지 관점을 고려하라.

 

1. 객체 생성을 보고 싶은가?

메모리 할당 스택 로깅이 프로세스 시작 시 활성화되었다면, 'malloc history' 를 사용하여 객체에 대한 백트레이스를 찾을 수 있다.

 

2. 메모리에 특정 객체나 주소를 참조하는 것을 보고 싶은가?

만약 메모리에 있는 특정 객체를 참조하는 것을 보고 싶다면, 'leaks' 와 그에 대한 여러 옵션을 사용하여 이를 확인할 수 있다.

 

3. 인스턴스의 크기를 알고 싶은가?

영역이나 인스턴스의 크기를 확인하고 싶다면, 'vmmap' 과 'heap' 도구를 사용하면 된다.

 

시작점으로서, 프로세스의 'memgraph' 에 대해 'summary flag'와 함께 'vmmap' 을 실행하는 것을 추천한다.

그리고 그 결과를 따라 내려가면서 문제를 파악하면 된다.

 

 

 

 

정리

1. iOS 메모리

iOS에서 메모리는 주로 'Clean', 'Dirty', 'Compressed' 세 가지로 나누어지고, 각 메모리에 대한 특징에 대해서 알아보았다. 또한 '메모리 경고' 가 어떤 이유로 나타나는지, 어떤 방법으로 해결해야 하는 것이 좋은지 등에 대해서 알아보았다.

 

이제 메모리에 대한 문제가 발생했을 때, 어떤 도구를 사용하여 메모리 프로파일링을 진행해야 하는지 알아본다.

 

2. VM Tracker

메모리 프로파일링에 탁월한 도구로, 앱의 'Dirty' 및 'Compressed '메모리 사용량에 대한 정보를 제공한다.

 

3. VM Memory Trace

앱의 가상 메모리 시스템 성능에 대한 깊은 이해를 제공한다. 

이것으로 'page cache hits', 'page zero fills' 등의 정보를 확인하는데 유용하다.

 

4. Xcode Debugger

앱이 메모리 사용량의 한계를 넘어서면, Xcode는 이러한 예외를 잡아내고 앱을 일시 중지시킨다.

그러면 개발자는 'Memgraph' 파일을 통해 메모리 분석을 시작해야 한다.

'Memgraph' 는 다양한 'Command-line' 툴과 함께 효과적으로 사용이 가능하다.

 

5. vmmap

프로세스에 할당된 각 가상 메모리 영역의 크기, 속성, 상태에 대한 자세한 정보를 알 수 있다.

중요한 것은 'Dirty', 'Swapped' 메모리가 앱의 전체 메모리 사용량에 미치는 영향을 보는 것.

 

6. Leaks

메모리 누수가 발생한 객체, 그 객체들이 속한 순환 참조도 보여준다.

만약 'malloc stack loggin' 이 활성화되어 있다면, 관련 백트레이스까지 제공해줌.

 

7. Heap

프로세스 힙 내의 객체 할당에 대한 정보를 제공한다.

'Memgraph' 와 함께 사용하여 어떤 객체가 가장 큰 메모리를 사용하고 있는지, 클래스의 각 인스턴스에 대한 주소는 어떤지 확인할 수 있음.

 

8. malloc stack logging

각 할당에 대한 백트레이스를 기록해준다.

'malloc history' 와 'Memgraph' 를 통해 특정 인스턴스의 백트레이스를 확인할 수 있다.

백트레이스를 가지고 어떤 코드가 문제가 되는지 확인할 수 있음.

 

 

이 세션을 통해 iOS 메모리의 매커니즘에 대해서 알 수 있었고, 메모리 문제에 관해 어떤 디버깅 전략을 사용해야하는지, 어떤 도구들을 사용할 수 있는지 학습할 수 있었다.

부족한 부분은 이 도구들을 활용하는 것은 좋지만, 관련 도구를 사용했을 때, 찍히는 로그들을 이해할 수 있어야 한다는 점이다. 

 

 

 

Reference

https://developer.apple.com/videos/play/wwdc2018/416