본문 바로가기
iOS 문서/WWDC

[한글 번역] WWDC21 - Detect and diagnose memory issues

by 초가을우엉차 2022. 6. 11.

Detect and diagnose memory issues

 ▶ 메모리 문제 감지 및 진단

 

 

1. Hi, my name is Tanuja, and I'm an engineer on the OS Performance team.

 ▶  안녕하세요, 제 이름은 Tanuja이고 OS 성능 팀의 엔지니어입니다.

 

2. Today Stefan and I are going to talk about how to detect and diagnose memory issues in your applications.

 ▶  오늘 Stefan과 저는 애플리케이션에서 메모리 문제를 감지하고 진단하는 방법에 대해 이야기할 것입니다.

 

3. We will start with looking into the impact of an application's memory footprint.

 ▶  응용 프로그램의 메모리 공간이 미치는 영향부터 살펴보겠습니다.

 

4. We will then talk about the tools to profile your memory usage and the types of memory issues you may encounter.

 ▶  그런 다음 메모리 사용량을 프로파일링하는 도구와 발생할 수 있는 메모리 문제 유형에 대해 설명합니다.

 

5. Let's jump right in.

 ▶  바로 가자.

 

6. One question you might immediately ask is, why should I care about my application's memory footprint? The key reason is that it improves your app's user experience tremendously.

 ▶  즉시 물어볼 수 있는 한 가지 질문은 응용 프로그램의 메모리 사용 공간에 관심을 가져야 하는 이유입니다. 주요 이유는 앱의 사용자 경험을 엄청나게 향상시키기 때문입니다.

 

7. There is a finite amount of memory on the system and monitoring your app's memory use can prevent the system from terminating your app to reclaim that memory.

 ▶  시스템에는 제한된 양의 메모리가 있으며 앱의 메모리 사용을 모니터링하면 시스템에서 해당 메모리를 회수하기 위해 앱을 종료하지 못할 수 있습니다.

 

8. This means your app can preserve its state when in the background, which is great, because loading into memory takes time, and keeping your memory footprint compact increases the chance of your application remaining in memory, leading to faster app activations.

 ▶  이는 앱이 백그라운드에 있을 때 상태를 유지할 수 있음을 의미합니다. 메모리에 로드하는 데 시간이 걸리고 메모리 공간을 작게 유지하면 애플리케이션이 메모리에 남아 있을 가능성이 높아져 앱 활성화가 빨라지기 때문에 좋습니다.

 

9. Reducing your memory use also results in a dynamic, responsive experience which is exactly what your users want as they explore your new features.

 ▶  메모리 사용을 줄이면, 사용자가 새로운 기능을 탐색할 때 정확히 원하는 동적이고 반응적인 경험을 얻을 수 있습니다.

 

10. By being strategic about with what your app has loaded into memory, your app can avoid the cost of waiting to reclaim memory as your user interacts with your app.

 ▶  앱이 메모리에 로드한 항목에 대해 전략적으로 사용함으로써, 앱은 사용자가 앱과 상호 작용할 때 메모리 회수를 기다리는 비용을 피할 수 있습니다.

 

11. Being strategic about your memory usage also opens the door to a wider range of features you could add to your app, such as loading videos, including animations, and a whole lot more.

 ▶  메모리 사용을 전략적으로 하면 애니메이션을 포함한 동영상 로드 등 앱에 추가할 수 있는 다양한 기능을 사용할 수 있습니다.

 

12. Finally, our devices are constantly evolving over time, and our newer devices have more physical memory than before.

 ▶  마지막으로, 우리의 장치는 시간이 지남에 따라 지속적으로 진화하고 있으며 최신 장치에는 이전보다 더 많은 물리적 메모리가 있습니다.

 

13. By reducing your memory footprint, your app will be just as performant on older devices, increasing the audience that can enjoy your app.

 ▶  메모리 사용 공간을 줄임으로써 앱은 구형 기기에서와 동일한 성능을 발휘하여 앱을 즐길 수 있는 사용자를 늘립니다.

 

14. By monitoring your app's memory footprint, your app will activate faster, be more responsive, handle complex features, and be performant on a wider range of devices.

 ▶  앱의 메모리 사용 공간을 모니터링하면, 앱이 더 빠르게 활성화되고 응답성이 향상되며 복잡한 기능을 처리하고 더 다양한 기기에서 성능을 발휘할 수 있습니다.

 

15. Let's now take a look at what makes up your memory footprint.

 ▶  이제 메모리 공간을 구성하는 요소를 살펴보겠습니다.

 

16. There are three categories we use to break down your application's memory profile: dirty, compressed, and clean memory.

 ▶  애플리케이션의 메모리 프로필을 분류하는 데 사용하는 세 가지 범주(더티, 압축 및 클린 메모리)가 있습니다.

 

17. Let's take a quick look at what each of these includes.

 ▶  이들 각각이 무엇을 포함하는지 간단히 살펴보자.

 

18. Dirty memory consists of memory written by your application.

 ▶  더티 메모리는 애플리케이션에서 작성한 메모리로 구성됩니다.

 

19. It also includes all heap allocations such as when you use malloc, decoded image buffers, and frameworks.

 ▶  또한 malloc, 디코딩된 이미지 버퍼 및 프레임워크를 사용할 때와 같은 모든 힙 할당이 포함됩니다.

 

20. Compressed memory refers to any dirty pages that haven't recently been accessed that the memory compressor has compressed.

 ▶  압축된 메모리는 메모리 압축기가 압축한 최근에 액세스하지 않은 모든 더티 페이지를 나타냅니다.

 

21. These pages will be decompressed on access.

 ▶  이 페이지는 액세스 시 압축이 해제됩니다.

 

22. Note that we do not have the concept of swap on iOS, which is specific to macOS.

 ▶  iOS에는 macOS에만 해당하는 스왑 개념이 없습니다.

 

23. And finally, we have clean memory.

 ▶  마지막으로 클린 메모리가 있습니다.

 

24. Clean memory is memory that has not been written to or data that can be paged out.

 ▶  클린 메모리는 기록되지 않은 메모리 또는 페이지 아웃할 수 있는 데이터입니다.

 

25. For example, these can be memory mapped files such as images that are on disk but loaded into memory.

 ▶  예를 들어 디스크에 있지만 메모리에 로드되는 이미지와 같은 메모리 매핑된 파일이 될 수 있습니다.

 

26. Or they can be frameworks.

 ▶  또는 프레임워크가 될 수 있습니다.

 

27. When we refer your application's memory footprint, we're really talking the your app's dirty memory and compressed memory together.

 ▶  애플리케이션의 메모리 공간을 참조할 때, 실제로는 앱의 더티 메모리와 압축 메모리를 함께 말하는 것입니다.

 

28. Clean memory does not count here.

 ▶  깨끗한 메모리는 여기에 포함되지 않습니다.

 

29. This is a high-level understanding of your memory footprint.

 ▶  이것은 메모리 풋프린트에 대한 높은 수준의 이해입니다.

 

30. For a more in-depth, detailed explanation, we recommend you check out the iOS memory deep dive talk from WWDC 2018.

 ▶  더 심도 있고 자세한 설명은 WWDC 2018에서 iOS 메모리 딥다이브 토크를 확인하시길 권장합니다..

 

31. Let's now take a look at the tools you can use to profile your memory footprint.

 ▶  이제 메모리 사용량을 프로파일링하는 데 사용할 수 있는 도구를 살펴보겠습니다.

 

32. Xcode offers a suite of tools to help monitor your app's memory performance throughout both the development and production workflows.

 ▶  Xcode는 개발 및 프로덕션 워크플로 전체에서 앱의 메모리 성능을 모니터링하는 데 도움이 되는 도구 모음을 제공합니다.

 

33. The XCTest framework helps you monitor your memory footprint directly in your project's unit and UI tests, while MetricKit and the Xcode Organizer allow you to monitor memory metrics in production from your customers.

 ▶  XCTest 프레임워크는 프로젝트의 단위 및 UI 테스트에서 직접 메모리 공간을 모니터링하는 데 도움이 되며, MetricKit 및 Xcode Organizer를 사용하면 고객의 프로덕션에서 메모리 메트릭을 모니터링할 수 있습니다.

 

34. The continuation of this talk will be in the context of using performance XCTests.

 ▶  이 강연은 성능 XCTest를 사용하는 맥락에서 계속될 것입니다.

 

35. But note that these techniques still apply to general memory triage and investigations.

 ▶  그러나 이러한 기술은 여전히 ​​일반 메모리 분류 및 조사에 적용됩니다.

 

36. Using performance XCTests, you can measure system resources such as memory utilization, CPU usage, disk writes, and a whole lot more.

 ▶  성능 XCTest를 사용하여 메모리 사용률, CPU 사용률, 디스크 쓰기 등과 같은 시스템 리소스를 측정할 수 있습니다.

 

37. Let's take a look at an example test together.

 ▶  예제 테스트를 함께 살펴보겠습니다.

 

38. Let's say I'm an app developer at Meal Planner, an app that helps you organize what you will eat in a week, and I want to measure the memory usage of this new save meal feature I've added that lets user download the recipe to their device.

 ▶  내가 일주일 동안 먹을 음식을 정리하는 데 도움이 되는 앱인 Meal Planner의 앱 개발자이고 사용자가 레시피를 다운로드할 수 있도록 추가한 이 새로운 식사 저장 기능의 메모리 사용량을 측정하고 싶다고 가정해 보겠습니다. 그들의 장치에.

 

39. In my performance test, I'm using the measure(metrics:options:block:) API and I'm specifying that I want to measure the memory use of my targeted application.

 ▶  내 성능 테스트에서 나는 measure(metrics:options:block:) API를 사용하고 있으며 대상 애플리케이션의 메모리 사용을 측정하고 싶다고 지정하고 있습니다.

 

40. In the body of the measure block, I'm launching the application, manually telling the measure API to start measuring, and then tapping on the save meal button.

 ▶  측정 블록의 본문에서 애플리케이션을 시작하고 측정 API에 측정을 시작하도록 수동으로 지시한 다음 식사 저장 버튼을 탭합니다.

 

41. I wait up to 30 seconds for the recipe download to complete by checking for an update in the UI.

 ▶  UI에서 업데이트를 확인하여, 레시피 다운로드가 완료될 때까지 최대 30초를 기다립니다.

 

42. Now I can run this test directly in Xcode's UI to view my measurements.

 ▶  이제 Xcode의 UI에서 직접 이 테스트를 실행하여 내 측정값을 볼 수 있습니다.

 

43. I can access my measurements by clicking on the gray diamond next to my test.

 ▶  내 테스트 옆에 있는 회색 다이아몬드를 클릭하여 내 측정값에 액세스할 수 있습니다.

 

44. The results popover UI has a drop down that shows me which metrics were measured.

 ▶  결과 팝오버 UI에는 측정된 메트릭을 보여주는 드롭다운이 있습니다.

 

45. The bar graph on the bottom shows me the measurements for each individual iteration.

 ▶  하단의 막대 그래프는 각 개별 반복에 대한 측정값을 보여줍니다.

 

46. The average of all five iterations is computed and displayed.

 ▶  모든 5회 반복의 평균이 계산되고 표시됩니다.

 

47. I can now decide if I want to set this run's average as my baseline for future tests to be compared against.

 ▶  이제 이 실행의 평균을 향후 테스트와 비교할 기준으로 설정할지 결정할 수 있습니다.

 

48. A future run of the test would now fail if its average is greater than the set baseline.

 ▶  평균이 설정된 기준보다 크면 향후 테스트 실행이 실패합니다.

 

49. We call this deviation from the set baseline a regression.

 ▶  우리는 설정된 기준선으로부터의 이 편차를 회귀라고 부릅니다.

 

50. A regression indicates that we should stop, investigate, and fix our code to make sure that the test passes.

 ▶  회귀는 테스트를 통과하도록 코드를 중지, 조사 및 수정해야 함을 나타냅니다.

 

51. We are excited to share that in Xcode 13, we've added in a new feature to collect diagnostics to help triage these test regressions.

 ▶  Xcode 13에 이러한 테스트 회귀를 분류하는 데 도움이 되는 진단을 수집하는 새로운 기능이 추가되었음을 공유하게 되어 기쁩니다.

 

52. There are two diagnostics that we find valuable: ktrace files and memory graphs.

 ▶  ktrace 파일과 메모리 그래프라는 두 가지 진단이 중요합니다.

 

53. Ktrace files are powerful and versatile.

 ▶  Ktrace 파일은 강력하고 다재다능합니다.

 

54. They can be used for general system investigations, or they can be focused on specific issues, such as diving into the rendering pipeline when investigating hitches or looking into reasons for why your main thread might be blocked, resulting in a hang.

 ▶  일반적인 시스템 조사에 사용할 수도 있고, 장애를 조사할 때 렌더링 파이프라인에 뛰어들거나 메인 스레드가 차단되어 정지가 발생할 수 있는 이유를 조사하는 것과 같은 특정 문제에 집중할 수 있습니다.

 

55. These ktrace files can be opened and analyzed in Instruments using your normal workflow.

 ▶  이러한 ktrace 파일은 일반 워크플로를 사용하여 Instruments에서 열고 분석할 수 있습니다.

 

56. The second diagnostic is a memory graph which are great for memory-specific investigations.

 ▶  두 번째 진단은 메모리 관련 조사에 적합한 메모리 그래프입니다.

 

57. Memory graphs can be used with Xcode's visual debugger as well as a variety of command line tools, some of which we'll cover later in this talk.

 ▶  메모리 그래프는 Xcode의 시각적 디버거는 물론 다양한 명령줄 도구와 함께 사용할 수 있으며, 이 중 일부는 이 강연의 뒷부분에서 다룰 것입니다.

 

58. A memory graph is essentially a snapshot of your process's address space at an instance in time.

 ▶  메모리 그래프는 본질적으로 한 인스턴스에서 프로세스 주소 공간의 스냅샷입니다.

 

59. Memgraphs record the address and size of each virtual memory region and each allocated malloc block, as well as pointers between those regions and blocks.

 ▶  Memgraph는 각 가상 메모리 영역과 할당된 각 malloc 블록의 주소와 크기, 그리고 해당 영역과 블록 간의 포인터를 기록합니다.

 

60. This allows you to inspect individual objects on the heap, view data regions associated with linked frameworks, and more.

 ▶  이를 통해 힙의 개별 개체를 검사하고 연결된 프레임워크와 연결된 데이터 영역 등을 볼 수 있습니다.

 

61. XCTest automatically enables malloc stack logging, which captures backtraces for newly allocated objects.

 ▶  XCTest는 새로 할당된 개체에 대한 역추적을 캡처하는 malloc 스택 로깅을 자동으로 활성화합니다.

 

62. To enable diagnostic collection, use the xcodebuild command line tool in conjunction with the enablePerformanceTestsDiagnostics flag.

 ▶  진단 수집을 활성화하려면 xcodebuild 명령줄 도구를 enablePerformanceTestsDiagnostics 플래그와 함께 사용하세요.

 

63. This flag will enable ktrace collection for nonmemory metrics and memgraphs for memory metrics.

 ▶  이 플래그는 비메모리 메트릭에 대한 ktrace 수집 및 메모리 메트릭에 대한 memgraph를 활성화합니다.

 

64. Once our previously written performance test is done running, we see the following printed to our console.

 ▶  이전에 작성한 성능 테스트가 실행되면 콘솔에 다음이 인쇄되는 것을 볼 수 있습니다.

 

65. This is quite a lot, but there are a few key things to look for.

 ▶  이것은 꽤 많지만 찾아야 할 몇 가지 핵심 사항이 있습니다.

 

66. The first thing to look for is if the test failed or passed.

 ▶  가장 먼저 확인해야 할 것은 테스트가 실패하거나 통과했는지 여부입니다.

 

67. In this case, the test failed.

 ▶  이 경우 테스트는 실패했습니다.

 

68. The output also calls out that the test failed specifically due to a regression.

 ▶  또한 출력은 특히 회귀로 인해 테스트가 실패했음을 나타냅니다.

 

69. Our new average is 12% worse than our baseline.

 ▶  새로운 평균은 기준보다 12% 더 나쁩니다.

 

70. Finally, we can find the path to our xcresult bundle.

 ▶  마지막으로 xcresult 번들의 경로를 찾을 수 있습니다.

 

71. When we open the xcresult bundle in Xcode, we see the memory measurements at the top next to the test name.

 ▶  Xcode에서 xcresult 번들을 열면 상단 테스트 이름 옆에 메모리 측정값이 표시됩니다.

 

72. We can then expand the test logs and towards the bottom, we can find our attached memgraphs.

 ▶  그런 다음 테스트 로그를 확장하고 아래쪽으로 갈수록 첨부된 memgraph를 찾을 수 있습니다.

 

73. Once downloaded and unzipped, we find 2 memgraphs.

 ▶  다운로드하고 압축을 풀면 2개의 memgraphs를 찾습니다.

 

74. This is because we append an additional iteration to your test to enable malloc stack logging.

 ▶  이는 malloc 스택 로깅을 활성화하기 위해 테스트에 추가 반복을 추가하기 때문입니다.

 

75. We collect an initial memgraph, prefixed with pre, at the beginning of the measured iteration, and we collect a second memgraph, prefixed with post, at the end of the iteration.

 ▶  측정된 반복이 시작될 때 pre가 붙은 초기 memgraph를 수집하고 반복이 끝날 때 post가 붙은 두 번째 memgraph를 수집합니다.

 

76. This allows you to analyze the memory growth over the period of one single iteration if needed.

 ▶  이를 통해 필요한 경우 단일 반복 기간 동안 메모리 증가를 분석할 수 있습니다.

 

77. Now with ktrace files and memory graphs with malloc stack logging enabled, you are ready to not just answer if a regression occurred but also why did the regression occur? I'll now hand it off to my colleague, Stefan, to talk about the types of memory issues you may encounter when looking into your collected memgraph diagnostics.

 ▶  이제 ktrace 파일과 malloc 스택 로깅이 활성화된 메모리 그래프를 사용하여 회귀가 발생했는지 뿐만 아니라 회귀가 발생한 이유에 대해서도 대답할 준비가 되었습니다. 이제 수집한 memgraph 진단을 조사할 때 발생할 수 있는 메모리 문제 유형에 대해 동료인 Stefan에게 전달하겠습니다.

 

78. Thanks, Tanuja.

 ▶  고마워, 타누자.

 

79. Hi, everyone.

 ▶  안녕하세요, 여러분.

 

80. I'm Stefan, an engineer on the OS Performance Team.

 ▶  저는 OS 성능 팀의 엔지니어인 Stefan입니다.

 

81. I'll be going over some common memory issues you might find in your app as well as how you can diagnose, fix, and prevent them.

 ▶  앱에서 발견할 수 있는 몇 가지 일반적인 메모리 문제와 이러한 문제를 진단, 수정 및 방지하는 방법을 살펴보겠습니다.

 

82. I'll go over two types of memory issues: leaks and heap issues, which can be broken down into heap allocation regressions and fragmentation issues.

 ▶  힙 할당 회귀 및 조각화 문제로 나눌 수 있는 누수 및 힙 문제의 두 가지 유형의 메모리 문제를 살펴보겠습니다.

 

83. This is not an exhaustive list, but it does cover some of the most common issues.

 ▶  이것은 완전한 목록은 아니지만 가장 일반적인 문제 중 일부를 다룹니다.

 

84. I'll also cover some command line workflows that can be used to diagnose these issues.

 ▶  또한 이러한 문제를 진단하는 데 사용할 수 있는 몇 가지 명령줄 워크플로를 다룰 것입니다.

 

85. For a more in-depth summary of the command line tools, check out the iOS memory deep dive talk from WWDC 2018.

 ▶  명령줄 도구에 대한 더 자세한 요약은 WWDC 2018의 iOS 메모리 심층 토론을 확인하세요..

 

86. Let's start by discussing memory leaks.

 ▶  메모리 누수에 대해 논의하는 것으로 시작하겠습니다.

 

87. A leak occurs when the process allocates an object and loses all references to it without ever deallocating it.

 ▶  프로세스가 개체를 할당하고 할당을 취소하지 않고 개체에 대한 모든 참조를 잃을 때 누수가 발생합니다.

 

88. Here I have an example object graph, where the gray arrows denote references between objects.

 ▶  여기에 회색 화살표가 개체 간의 참조를 나타내는 개체 그래프의 예가 있습니다.

 

89. Notice that every object has at least one reference to it.

 ▶  모든 객체에는 적어도 하나의 참조가 있습니다.

 

90. Notice the dotted line reference from object A to object B.

 ▶  A 개체에서 B 개체로의 점선 참조에 주목하세요..

 

91. Let's say I set this reference to nil, removing it.

 ▶  이 참조를 nil로 설정하고 제거한다고 가정해 보겠습니다.

 

92. With that reference gone, object B has been leaked.

 ▶  해당 참조가 사라지면서 객체 B가 유출되었습니다.

 

93. There are no references to it at all.

 ▶  그에 대한 언급은 전혀 없습니다.

 

94. It's still dirty, but the process has no way to reference it and no way to free it until it exits.

 ▶  여전히 더럽지만 프로세스가 이를 참조할 방법이 없고 종료될 때까지 해제할 방법이 없습니다.

 

95. For this reason, you should always fix leaks.

 ▶  이러한 이유로 항상 누수를 수정해야 합니다.

 

96. A common way objects leak in Swift is via retain cycles.

 ▶  Swift에서 객체가 누출되는 일반적인 방법은 유지 주기를 사용하는 것입니다.

 

97. In this diagram, objects A and B are in a retain cycle.

 ▶  이 다이어그램에서 개체 A와 B는 유지 주기에 있습니다.

 

98. They reference one another, but there are no external references to either of them.

 ▶  그것들은 서로를 참조하지만 어느 쪽에도 외부 참조가 없습니다.

 

99. This means the process can't access or free either of them, so they're considered leaked.

 ▶  이는 프로세스가 둘 중 하나에 액세스하거나 해제할 수 없음을 의미하므로 유출된 것으로 간주됩니다.

 

100. Fortunately, most objects in Swift are managed by Swift's automatic reference counting system, or ARC, which prevents a lot of leaks.

 ▶  다행스럽게도 Swift의 대부분의 객체는 Swift의 자동 참조 카운팅 시스템(ARC)에 의해 관리되어 많은 누출을 방지합니다.

 

101. If you're working with objects not managed by ARC, such as unsafe pointers, make sure you deallocate them before you lose your references to them.

 ▶  안전하지 않은 포인터와 같이 ARC에서 관리하지 않는 개체로 작업하는 경우 참조를 잃기 전에 할당을 해제해야 합니다.

 

102. Even ARC managed objects are susceptible to being part of a retain cycle.

 ▶  ARC 관리 객체도 보유 주기의 일부가 되기 쉽습니다.

 

103. So avoid creating strong circular references in your code.

 ▶  따라서 코드에서 강력한 순환 참조를 생성하지 마십시오.

 

104. If a circular reference is absolutely necessary, consider a weak reference instead, because weak references won't prevent objects from being deallocated.

 ▶  순환 참조가 절대적으로 필요한 경우 약한 참조가 객체의 할당 해제를 방지하지 않으므로 대신 약한 참조를 고려하십시오.

 

105. Let's look at an example from the Meal Planner app.

 ▶  Meal Planner 앱의 예를 살펴보겠습니다.

 

106. Tanuja has sent me some pre and post memgraphs from the failing XCTest.

 ▶  Tanuja는 실패한 XCTest에서 몇 가지 사전 및 사후 memgraph를 보냈습니다.

 

107. Right away, I want to check for leaks in the post memgraph.

 ▶  바로 post memgraph에 누수가 있는지 확인하고 싶습니다.

 

108. To do this, I run leaks on the memgraph.

 ▶  이를 위해 memgraph에서 누수를 실행합니다.

 

109. This shows me some helpful information about any leaks I have.

 ▶  이것은 내가 가진 누출에 대한 몇 가지 유용한 정보를 보여줍니다.

 

110. The output shows I have 4 leaks for a total of 240 leaked bytes.

 ▶  출력은 총 240개의 누출된 바이트에 대해 4개의 누출이 있음을 보여줍니다.

 

111. Further down, the output includes a detailed view of the object graph for each of the leaks, which gives me some clues as to what might be leaking.

 ▶  더 아래로, 출력에는 각 누출에 대한 개체 그래프의 자세한 보기가 포함되어 있어 누출 가능성에 대한 몇 가지 단서를 제공합니다.

 

112. The top of the object graph says ROOT CYCLE, which means I'm dealing with a retain cycle.

 ▶  개체 그래프의 맨 위에는 ROOT CYCLE이라고 표시되어 있는데, 이는 내가 유지 주기를 다루고 있음을 의미합니다.

 

113. There are some useful symbols here.

 ▶  여기에 몇 가지 유용한 기호가 있습니다.

 

114. Looks like this retain cycle probably includes meal plan and menu item objects.

 ▶  이 유지 주기에는 식사 계획과 메뉴 항목 개체가 포함될 수 있습니다.

 

115. Because malloc stack logging is enabled for XCTests, the output also includes an allocation call stack for each leak.

 ▶  XCTest에 대해 malloc 스택 로깅이 활성화되어 있기 때문에 출력에는 각 누출에 대한 할당 호출 스택도 포함됩니다.

 

116. This is extremely useful for finding which objects leaked.

 ▶  이것은 누출된 개체를 찾는 데 매우 유용합니다.

 

117. Often, you'll want to find the section of the call stack with symbols from your code.

 ▶  종종 코드의 기호가 있는 호출 스택 섹션을 찾고 싶을 것입니다.

 

118. Here's the portion of the call stack from my code.

 ▶  다음은 내 코드의 호출 스택 부분입니다.

 

119. The leaking meal plan object is allocated in the populateMealData function.

 ▶  새는 식단 개체는 populateMealData 함수에 할당됩니다.

 

120. I'll open up Xcode and see if I can fix the issue.

 ▶  Xcode를 열고 문제를 해결할 수 있는지 확인하겠습니다.

 

121. Here's the populateMealData function I saw in leaks.

 ▶  다음은 누수에서 본 populateMealData 함수입니다.

 

122. Here I'm allocating a meal plan object and a menu item object, which are the two objects I saw in my retain cycle.

 ▶  여기에서는 내가 유지 주기에서 본 두 개의 개체인 식사 계획 개체와 메뉴 항목 개체를 할당하고 있습니다.

 

123. Hmm, this addMealToMealPlan function looks a bit suspicious.

 ▶  흠, 이 addMealToMealPlan 함수는 약간 의심스러워 보입니다.

 

124. I'll take a look.

 ▶  내가 볼게요.

 

125. Hmm, so it looks like I'm calling addItem on the meal plan, but I'm also calling addPlan on the menu item.

 ▶  음, 식단에서 addItem을 호출하는 것처럼 보이지만 메뉴 항목에서도 addPlan을 호출하고 있습니다.

 

126. This is for a feature allowing us to see all the items for a plan but also which plan an item is associated with.

 ▶  이것은 우리가 계획에 대한 모든 항목을 볼 수 있도록 하는 기능을 위한 것입니다. 또한 항목이 연결된 계획도 볼 수 있습니다.

 

127. Here in meal plan, addItem adds the menu item to an array, saving a reference to it.

 ▶  여기 식사 계획에서 addItem은 메뉴 항목을 배열에 추가하여 참조를 저장합니다.

 

128. And here in menu item, addPlan saves a reference to the meal plan.

 ▶  그리고 여기 메뉴 항목에서 addPlan은 식사 계획에 대한 참조를 저장합니다.

 

129. So this is definitely a retain cycle because they both hold a strong reference to each other.

 ▶  따라서 이것은 둘 다 서로에 대한 강력한 참조를 유지하기 때문에 확실히 유지 주기입니다.

 

130. Once populateMealData exits, both the meal plan and menu item objects will be out of scope, so there will be no external references to them.

 ▶  populateMealData가 종료되면 식사 계획과 메뉴 항목 개체가 모두 범위를 벗어나므로 해당 개체에 대한 외부 참조가 없습니다.

 

131. But they still reference each other, causing a leak.

 ▶  그러나 그들은 여전히 ​​서로를 참조하여 누출을 일으킵니다.

 

132. I should probably try to find a solution without a cyclical reference.

 ▶  나는 아마도 순환 참조 없이 해결책을 찾으려고 노력해야 할 것입니다.

 

133. But as a quick fix for now, I'll change menu item to use a weak reference for its meal plan object.

 ▶  그러나 지금은 빠른 수정으로 식사 계획 개체에 약한 참조를 사용하도록 메뉴 항목을 변경하겠습니다.

 

134. This breaks the retain cycle because we no longer have two cyclical strong references.

 ▶  더 이상 두 개의 순환적 강력한 참조가 없기 때문에 유지 주기가 중단됩니다.

 

135. Let's shift gears now to heap allocation regressions.

 ▶  이제 기어를 힙 할당 회귀로 전환해 보겠습니다.

 

136. The heap is simply a section of your process's address space where dynamically allocated objects are stored.

 ▶  힙은 단순히 동적으로 할당된 개체가 저장되는 프로세스 주소 공간의 한 부분입니다.

 

137. Heap allocation regressions are an increase in memory footprint due to the process allocating more objects on the heap than before.

 ▶  힙 할당 회귀는 이전보다 힙에 더 많은 개체를 할당하는 프로세스로 인한 메모리 공간의 증가입니다.

 

138. To reduce heap regressions, look to remove unused allocations and shrink unnecessarily large allocations.

 ▶  힙 회귀를 줄이려면 사용하지 않는 할당을 제거하고 불필요하게 큰 할당을 줄이십시오.

 

139. You should also pay attention to how much memory you hold at once.

 ▶  한 번에 얼마나 많은 메모리를 보유하고 있는지도 주의해야 합니다.

 

140. Deallocate memory you're no longer using and wait to allocate memory until you need it.

 ▶  더 이상 사용하지 않는 메모리 할당을 해제하고, 필요할 때까지 메모리 할당을 기다리십시오.

 

141. This will reduce your app's peak footprint, making it less likely to be terminated.

 ▶  이렇게 하면 앱의 최대 사용 공간이 줄어들어 종료될 가능성이 줄어듭니다.

 

142. So let's return now to the failing XCTest from the MealPlanner app and check for a heap regression.

 ▶  이제 MealPlanner 앱에서 실패한 XCTest로 돌아가 힙 회귀를 확인하겠습니다.

 

143. To understand where I should look, I'll run vmmap -summary on both the pre and post memgraphs to get a nice overview of where memory is being used.

 ▶  어디를 봐야 하는지 이해하기 위해 pre 및 post memgraphs 모두에서 vmmap -summary를 실행하여 메모리가 사용되는 위치에 대한 멋진 개요를 얻을 것입니다.

 

144. My footprint in the pre memgraph is around 112 megabytes.

 ▶  premgraph에서 내 발자국은 약 112MB입니다.

 

145. And in the post memgraph, my footprint is 125 megabytes, so that's about a 13 megabyte difference.

 ▶  그리고 post memgraph에서 내 발자국은 125MB이므로 약 13MB의 차이가 있습니다.

 

146. Further down, the output shows my process's memory usage broken down by region.

 ▶  더 아래로 출력에는 지역별로 분류된 내 프로세스의 메모리 사용량이 표시됩니다.

 

147. Because I suspect this is a heap allocation issue, I want to look at the regions starting with MALLOC_ because those regions contain all of my heap objects.

 ▶  이것이 힙 할당 문제라고 생각하기 때문에 MALLOC_로 시작하는 영역을 살펴보고 싶습니다. 해당 영역에 내 힙 개체가 모두 포함되어 있기 때문입니다.

 

148. Remember Tanuja's equation: Memory footprint = Dirty memory + Compressed Memory.

 ▶  Tanuja의 방정식을 기억하십시오: 메모리 풋프린트 = 더러운 메모리 + 압축 메모리.

 

149. In this tool, the term "swapped" means "compressed.

 ▶  이 도구에서 "swapped"라는 용어는 "압축된"을 의미합니다..

 

150. " So of these columns, I only care about "dirty size" and "swapped size.

 ▶  " 그래서 이 컬럼들 중 나는 "dirty size"와 "swapped size"에만 신경을 쓴다.

 

151. " And sure enough, the output shows that the MALLOC_LARGE region is holding about 13 megabytes of dirty memory.

 ▶  " 그리고 출력은 MALLOC_LARGE 영역이 약 ​​13MB의 더티 메모리를 보유하고 있음을 보여줍니다..

 

152. That's roughly equivalent to my regression size, so I definitely want to look into that.

 ▶  내 회귀 크기와 거의 동일하므로 확실히 살펴보고 싶습니다.

 

153. The next step is to figure out what kinds of objects are contributing to this 13 megabyte regression.

 ▶  다음 단계는 이 13MB 회귀에 기여하는 개체의 종류를 파악하는 것입니다.

 

154. To get that information, I'll run heap -diffFrom on my post memgraph.

 ▶  해당 정보를 얻으려면 내 게시물 memgraph에서 heap -diffFrom을 실행합니다.

 

155. I pass in my pre and post memgraphs as arguments.

 ▶  내 pre 및 post memgraphs를 인수로 전달합니다.

 

156. This shows me the objects that exist in the post memgraph heap but not in the pre memgraph heap.

 ▶  이것은 post memgraph 힙에는 있지만 pre memgraph 힙에는 없는 객체를 보여줍니다.

 

157. Near the top, the output shows I have around 13 megabytes of new objects in the post memgraph.

 ▶  상단 부근에서 출력은 post memgraph에 약 13MB의 새 개체가 있음을 보여줍니다.

 

158. Below, the heap memory is broken down by object class.

 ▶  아래에서 힙 메모리는 객체 클래스로 나뉩니다.

 

159. For each object class, the output shows the number of objects and the sum in bytes of those objects.

 ▶  각 객체 클래스에 대해 출력은 객체 수와 해당 객체의 합계(바이트)를 보여줍니다.

 

160. Right away, I notice that I have about 13 megabytes worth of this "non-object" type.

 ▶  바로 이 "비객체" 유형의 약 13MB 가치가 있음을 알 수 있습니다.

 

161. In Swift, this usually indicates raw malloced bytes.

 ▶  Swift에서 이것은 일반적으로 원시 malloced 바이트를 나타냅니다.

 

162. This type of object can be a bit tricky to track down, but there are some tools I can use to get some information.

 ▶  이러한 유형의 개체는 추적하기가 약간 까다로울 수 있지만 일부 정보를 얻는 데 사용할 수 있는 몇 가지 도구가 있습니다.

 

163. To start, I want the addresses of these non-objects.

 ▶  시작하려면 이러한 비객체의 주소를 원합니다.

 

164. I'll run heap -addresses to grab them.

 ▶  나는 그것들을 잡기 위해 heap-addresses를 실행할 것이다.

 

165. I'll specify that I only want non-objects whose size is at least 500 kilobytes.

 ▶  크기가 500KB 이상인 비객체만 원한다고 지정하겠습니다.

 

166. Aha.

 ▶  아하.

 

167. This non-object is about 13 megabytes, so it's a prime suspect in this investigation.

 ▶  이 비객체는 약 13MB이므로 이 조사에서 유력한 용의자입니다.

 

168. I'll grab its address and see if I can find some clues about what it is.

 ▶  주소를 가져와서 그것이 무엇인지에 대한 단서를 찾을 수 있는지 확인하겠습니다.

 

169. I have several options at this point.

 ▶  이 시점에서 몇 가지 옵션이 있습니다.

 

170. Each has its benefits depending on the situation, so I'll walk through each one briefly.

 ▶  각각은 상황에 따라 장단점이 있으므로 간략하게 하나씩 살펴보도록 하겠습니다.

 

171. One option I have is to run leaks --traceTree on this address.

 ▶  내가 가진 한 가지 옵션은 이 주소에서 누출 --traceTree를 실행하는 것입니다.

 

172. This gives me a tree of objects that reference this address.

 ▶  이렇게 하면 이 주소를 참조하는 개체 트리가 제공됩니다.

 

173. This is useful if I have a specific object I want to get more information about and my memgraph doesn't have malloc stack logging or MSL enabled.

 ▶  이것은 더 많은 정보를 얻고 싶은 특정 객체가 있고 memgraph에 malloc 스택 로깅이나 MSL이 활성화되어 있지 않은 경우에 유용합니다.

 

174. Remember that our XCTest memgraphs automatically have MSL enabled, but if you're ever working with a memgraph that doesn't, keep this tool in mind.

 ▶  XCTest memgraphs는 자동으로 MSL을 활성화하지만 그렇지 않은 memgraph로 작업하는 경우 이 도구를 염두에 두십시오.

 

175. I've highlighted the object in the tree that seems relevant.

 ▶  관련성이 있는 것으로 보이는 트리에서 개체를 강조 표시했습니다.

 

176. My large non-object probably has something to do with this meal data object in MKTCustomMeal PlannerCollectionViewCell.

 ▶  내 큰 비 개체는 아마도 MKTCustomMeal PlannerCollectionViewCell의 이 식사 데이터 개체와 관련이 있을 것입니다.

 

177. I can also run leaks --referenceTree.

 ▶  "leaks" --referenceTree를 실행할 수도 있습니다.

 

178. This gives me a top-down reference tree of all the memory in my process with a best guess of which objects are the roots.

 ▶  이것은 어떤 객체가 루트인지 가장 잘 추측하여 내 프로세스의 모든 메모리에 대한 하향식 참조 트리를 제공합니다.

 

179. With this output, I can get a sense of where memory is aggregated in my app.

 ▶  이 출력을 통해 내 앱에서 메모리가 집계되는 위치를 파악할 수 있습니다.

 

180. This tool is extremely helpful if I know I have a large regression but I don't know which specific objects are responsible.

 ▶  이 도구는 큰 회귀가 있다는 것을 알고 있지만 어떤 특정 개체가 책임이 있는지 모르는 경우에 매우 유용합니다.

 

181. I can pass the --groupByType argument to group like types together, shrinking the output and making it a bit easier to parse.

 ▶  --groupByType 인수를 유사한 유형을 함께 그룹화하여 출력을 축소하고 구문 분석하기 쉽게 만들 수 있습니다.

 

182. Oftentimes, a large chunk of the regression will be grouped under a single node in this tree, making it easier to find clues about what that memory is.

 ▶  종종 회귀의 큰 덩어리가 이 트리의 단일 노드 아래에 그룹화되어 해당 메모리가 무엇인지에 대한 단서를 더 쉽게 찾을 수 있습니다.

 

183. Again, I've highlighted the section showing the relevant objects.

 ▶  다시 말하지만, 관련 개체를 보여주는 섹션을 강조 표시했습니다.

 

184. Here's that same meal data object I saw in the leaks -traceTree output.

 ▶  다음은 leak -traceTree 출력에서 ​​본 것과 동일한 식사 데이터 개체입니다.

 

185. The output shows that there's about 13 megabytes worth of memory allocated to this meal data object.

 ▶  출력은 이 식사 데이터 개체에 약 13MB 상당의 메모리가 할당되었음을 보여줍니다.

 

186. I'd love to know how this object is being allocated.

 ▶  이 개체가 어떻게 할당되는지 알고 싶습니다.

 

187. Because my memgraph has MSL enabled, I can use malloc_history -fullStacks to figure that out.

 ▶  내 memgraph에 MSL이 활성화되어 있기 때문에 malloc_history -fullStacks를 사용하여 이를 파악할 수 있습니다.

 

188. I pass in the address of the large non-object I grabbed from heap -addresses earlier.

 ▶  이전에 heap-addresses에서 가져온 큰 non-object의 주소를 전달합니다.

 

189. And I get an allocation call stack for the object at that address.

 ▶  그리고 그 주소에 있는 객체에 대한 할당 호출 스택을 얻습니다.

 

190. This is extremely useful when I have MSL enabled and I have the address of the object I care about.

 ▶  이것은 내가 MSL을 활성화하고 내가 관심 있는 개체의 주소를 알고 있을 때 매우 유용합니다.

 

191. So looks like my meal data object was allocated in the saveMeal function, shown here on line 3.

 ▶  그래서 제 식사 데이터 객체가 3행에 나와 있는 saveMeal 함수에 할당된 것 같습니다..

 

192. I'll head over to Xcode to see what's going on.

 ▶  무슨 일이 일어나고 있는지 보기 위해 Xcode로 가겠습니다.

 

193. Here's the saveMeal function inside my custom cell view controller.

 ▶  다음은 내 사용자 지정 셀 보기 컨트롤러 내부의 saveMeal 기능입니다.

 

194. And here's the culprit.

 ▶  그리고 여기 범인이 있습니다.

 

195. I'm allocating this raw buffer here and then wrapping it with the meal data object.

 ▶  이 원시 버퍼를 여기에 할당한 다음 식사 데이터 개체로 래핑합니다.

 

196. I'm only allocating this buffer so that I can populate it and save the result to disk.

 ▶  버퍼를 채우고 결과를 디스크에 저장할 수 있도록 이 버퍼만 할당합니다.

 

197. Once I'm done saving to disk, I don't really need this buffer anymore.

 ▶  디스크에 저장을 마치면 이 버퍼가 더 이상 필요하지 않습니다.

 

198. So why is it sticking around? Well, meal data is a class member, so as long as this class instance exists, the reference will stick around.

 ▶  그래서 왜 붙어있는거야? 음, 식사 데이터는 클래스 멤버이므로 이 클래스 인스턴스가 존재하는 한 참조는 계속 유지됩니다.

 

199. This means that when I hit saveMeal on any cell, that cell allocates and holds a large buffer that will stick around until that cell is destroyed.

 ▶  즉, 내가 아무 셀에서나 saveMeal을 누르면 해당 셀이 해당 셀이 파괴될 때까지 유지되는 큰 버퍼를 할당하고 보유합니다.

 

200. That memory could really add up if I'm saving multiple meals.

 ▶  내가 여러 끼를 저장한다면 그 기억은 정말로 더해질 수 있습니다.

 

201. So how can I fix this? One option would be to just define mealData in the saveMeal function, but I know it's used elsewhere in the class, so I don't want to do that.

 ▶  이 문제를 어떻게 고칠 수 있습니까? 한 가지 옵션은 saveMeal 함수에서 mealData를 정의하는 것이지만 클래스의 다른 곳에서 사용된다는 것을 알고 있으므로 그렇게 하고 싶지 않습니다.

 

202. Another way would be to set mealData to nil once I'm done writing it to disk.

 ▶  또 다른 방법은 디스크에 쓰기를 완료한 후 mealData를 nil로 설정하는 것입니다.

 

203. The data object in Swift is smart enough to automatically deallocate the buffer once I've lost my final reference to it, so the buffer won't stick around past the end of this function.

 ▶  Swift의 데이터 객체는 마지막 참조를 잃어버리면 버퍼를 자동으로 할당 해제할 만큼 충분히 똑똑하므로 버퍼는 이 함수의 끝을 지나도 남아있지 않습니다.

 

204. Lastly, let's talk about fragmentation.

 ▶  마지막으로 단편화(fragmentation)에 대해 알아보겠습니다.

 

205. Let's quickly go over how pages work in iOS.

 ▶  iOS에서 페이지가 어떻게 작동하는지 빠르게 살펴보겠습니다.

 

206. A page is a fixed size, indivisible chunk of memory that the system grants to your process.

 ▶  페이지는 시스템이 프로세스에 부여하는 고정된 크기의 분할할 수 없는 메모리 청크입니다.

 

207. Because pages are indivisible, when your process writes to any part of a page, the entire page is considered dirty, and your process will be charged for it, even if most of it is unused.

 ▶  페이지는 분할할 수 없기 때문에 프로세스가 페이지의 어느 부분에라도 쓸 때 전체 페이지는 더티(dirty)한 것으로 간주되며 대부분이 사용되지 않더라도 프로세스에 비용이 청구됩니다.

 

208. Fragmentation occurs when a process has dirty pages that are not 100% utilized.

 ▶  단편화는 프로세스에 100% 활용되지 않는 더티 페이지가 있을 때 발생합니다.

 

209. To understand how this happens, let's look at an example.

 ▶  이것이 어떻게 일어나는지 이해하기 위해 예를 살펴보겠습니다.

 

210. To start, I have 3 contiguous clean pages.

 ▶  시작하려면 3개의 연속적인 클린 페이지가 있습니다.

 

211. As the process runs, allocations begin filling up these pages, dirtying them.

 ▶  프로세스가 실행되면 할당이 이러한 페이지를 채우기 시작하여 더러워집니다.

 

212. When objects are deallocated, they create empty slots where they used to be marked "free memory" in the diagram.

 ▶  개체가 할당 해제되면 다이어그램에서 "사용 가능한 메모리"로 표시되었던 빈 슬롯이 생성됩니다.

 

213. However, these pages are still dirty because there are still some allocated objects on them.

 ▶  그러나 이 페이지에는 여전히 할당된 개체가 있기 때문에 여전히 더럽습니다.

 

214. The system will attempt to fill these empty slots with future allocations.

 ▶  시스템은 이러한 빈 슬롯을 향후 할당으로 채우려고 시도합니다.

 

215. Here I have a large incoming allocation notated by the box on the right.

 ▶  여기에 오른쪽 상자로 표시된 대규모 수신 할당이 있습니다.

 

216. Unfortunately, this incoming allocation is too large to fit in my free memory slots.

 ▶  불행히도 이 들어오는 할당이 너무 커서 여유 메모리 슬롯에 맞지 않습니다.

 

217. Even though the combined size of the empty slots is large enough, they aren't contiguous and they can't be used for a single allocation.

 ▶  빈 슬롯을 합친 크기가 충분히 크더라도 연속적이지 않고 단일 할당에 사용할 수 없습니다.

 

218. So because it couldn't fit in any existing free slots, the system placed my allocation on a new dirty page on the right side of the diagram.

 ▶  따라서 기존 여유 슬롯에 들어갈 수 없었기 때문에 시스템은 다이어그램의 오른쪽에 있는 새로운 더티 페이지에 내 할당을 배치했습니다.

 

219. The free memory slots remain unfilled and are considered fragmented memory.

 ▶  사용 가능한 메모리 슬롯은 채워지지 않은 상태로 남아 있으며 조각난 메모리로 간주됩니다.

 

220. The best way to reduce fragmentation is to allocate objects with similar lifetimes close to each other in memory.

 ▶  조각화를 줄이는 가장 좋은 방법은 수명이 비슷한 개체를 메모리에 할당하는 것입니다.

 

221. This helps ensure that all of those objects are freed together, giving the process large chunks of contiguous memory to work with for future allocations.

 ▶  이렇게 하면 이러한 모든 개체가 함께 해제되어 향후 할당을 위해 작업할 연속 메모리의 큰 청크를 프로세스에 제공하는 데 도움이 됩니다.

 

222. In this example, I manually allocated all the objects marked "my object," and I plan to free them at the same time.

 ▶  이 예에서는 "내 개체"로 표시된 모든 개체를 수동으로 할당했으며 동시에 해제할 계획입니다.

 

223. But I wasn't careful in my code, and the system ended up interleaving my objects with other objects.

 ▶  그러나 나는 내 코드에 주의하지 않았고, 시스템은 결국 내 개체를 다른 개체와 인터리빙하게 되었습니다.

 

224. Now, when I free all my objects, I have four slots of free memory, none of which are contiguous because they're broken up by these allocated objects.

 ▶  이제 모든 개체를 해제하면 4개의 여유 메모리 슬롯이 있습니다. 이 슬롯은 할당된 개체에 의해 분리되기 때문에 인접하지 않습니다.

 

225. This results in 50% fragmentation and four dirty pages.

 ▶  그 결과 50%의 조각화와 4개의 더티 페이지가 생성됩니다.

 

226. Not great.

 ▶  별로.

 

227. What if I instead wrote code to allocate all of my objects together? Now they all end up together on two pages.

 ▶  대신 모든 개체를 함께 할당하는 코드를 작성하면 어떻게 될까요? 이제 그들은 모두 두 페이지에서 함께 끝납니다.

 

228. And when I free my objects, the process frees up two clean pages for the system, resulting in only 2 dirty pages and 0% fragmentation.

 ▶  그리고 객체를 해제하면 프로세스가 시스템에 대해 2개의 클린 페이지를 해제하여 2개의 더티 페이지와 0% 조각화만 생성합니다.

 

229. Notice how fragmentation is a footprint multiplier.

 ▶  단편화가 어떻게 풋프린트 승수인지 주목하십시오.

 

230. 50% fragmentation doubled my footprint from 2 to 4 dirty pages.

 ▶  50% 조각화는 2개에서 4개의 더티 페이지로 내 공간을 두 배로 늘렸습니다.

 

231. In most real scenarios, some fragmentation is inevitable.

 ▶  대부분의 실제 시나리오에서 일부 단편화는 불가피합니다.

 

232. So as a rule of thumb, aim for about 25% fragmentation or less.

 ▶  따라서 일반적으로 약 25% 이하의 단편화를 목표로 합니다.

 

233. One way to reduce fragmentation is to use autorelease pools.

 ▶  단편화를 줄이는 한 가지 방법은 자동 릴리스 풀을 사용하는 것입니다.

 

234. An autorelease pool tells the system to release all objects allocated inside of it as soon as it goes out of scope.

 ▶  자동 해제 풀은 범위를 벗어나는 즉시 내부에 할당된 모든 개체를 해제하도록 시스템에 지시합니다.

 

235. This helps ensure that all objects created in the autorelease pool have similar lifetimes.

 ▶  이는 자동 릴리스 풀에서 생성된 모든 객체가 유사한 수명을 갖도록 하는 데 도움이 됩니다.

 

236. Although fragmentation can be an issue for all processes, long running processes can be especially prone, because there are lots of allocations and deallocations to potentially fragment the address space.

 ▶  단편화는 모든 프로세스에서 문제가 될 수 있지만, 주소 공간을 잠재적으로 단편화하는 할당 및 할당 해제가 많기 때문에 장기 실행 프로세스가 특히 취약할 수 있습니다.

 

237. If your app uses long running extensions, for example, be sure to take a look at fragmentation in those processes.

 ▶  예를 들어 앱이 장기 실행 확장을 사용하는 경우 해당 프로세스의 단편화를 살펴보십시오.

 

238. To take a quick look at my process's fragmentation, I can run vmmap -summary and scroll down to the bottom of the output.

 ▶  내 프로세스의 조각화를 빠르게 살펴보기 위해 vmmap -summary를 실행하고 출력의 맨 아래로 스크롤할 수 있습니다.

 

239. This section is divided into malloc zones.

 ▶  이 섹션은 malloc 영역으로 나뉩니다.

 

240. Each zone contains different types of allocations.

 ▶  각 영역에는 다른 유형의 할당이 포함됩니다.

 

241. Usually I would only care about the DefaultMallocZone, because that's where my heap allocations end up by default.

 ▶  일반적으로 DefaultMallocZone에 대해서만 관심을 가질 것입니다. 기본적으로 힙 할당이 끝나는 곳이기 때문입니다.

 

242. However, because this memgraph has MSL enabled, I actually care about the MallocStackLoggingLiteZone.

 ▶  그러나 이 memgraph에는 MSL이 활성화되어 있기 때문에 실제로 MallocStackLoggingLiteZone에 관심이 있습니다.

 

243. As long as MSL is enabled, this zone is where all the heap allocations end up.

 ▶  MSL이 활성화되어 있는 한 이 영역은 모든 힙 할당이 끝나는 곳입니다.

 

244. The % FRAG column shows me what percentage of my memory is wasted due to fragmentation in each malloc zone.

 ▶  % FRAG 열은 각 malloc 영역의 조각화로 인해 낭비되는 메모리의 백분율을 보여줍니다.

 

245. Some of these numbers are pretty large, but I only need to focus on the MallocStackLoggingLiteZone.

 ▶  이 숫자 중 일부는 꽤 크지만 MallocStackLoggingLiteZone에만 집중하면 됩니다.

 

246. That's because the MallocStackLoggingLiteZone has by far the largest share of dirty memory, with 4.

 ▶  그 이유는 MallocStackLoggingLiteZone이 4로 가장 많은 더티 메모리 점유율을 가지고 있기 때문입니다..

 

247. 3 megabytes out of 5 megabytes total.

 ▶  총 5MB 중 3MB입니다.

 

248. So I can ignore the other zones this time.

 ▶  그래서 이번에는 다른 영역을 무시할 수 있습니다.

 

249. The "dirty+swap frag size" column shows me exactly how much memory is wasted due to fragmentation in each malloc zone.

 ▶  "dirty+swap frag size" 열은 각 malloc 영역의 조각화로 인해 얼마나 많은 메모리가 낭비되는지 정확히 보여줍니다.

 

250. In my case, I'm wasting about 800K due to fragmentation.

 ▶  제 경우에는 단편화로 인해 약 800K를 낭비하고 있습니다.

 

251. This seems like a lot, but as I mentioned before, some fragmentation is inevitable.

 ▶  많은 것 같지만 앞서 언급했듯이 일부 단편화는 불가피합니다.

 

252. So as long as I'm sitting under 25% fragmentation, I'll consider this much waste acceptable.

 ▶  따라서 25% 조각화 미만에 있는 한 이 정도의 낭비를 허용할 수 있습니다.

 

253. Looks like I'm sitting at about 19% fragmentation in the MallocStackLoggingLiteZone.

 ▶  MallocStackLoggingLiteZone에서 약 19% 조각화에 앉아 있는 것 같습니다.

 

254. This is comfortably below the 25% rule of thumb, so I'm not concerned.

 ▶  이것은 25% 경험 법칙보다 편안하므로 걱정할 필요가 없습니다.

 

255. If I did have fragmentation issues, I could use the Allocations track in the Instruments tool.

 ▶  조각화 문제가 있는 경우 Instruments 도구에서 Allocations 트랙을 사용할 수 있습니다.

 

256. Specifically, I'd want to look at the allocations list view and see which objects were persisted and destroyed in my area of interest.

 ▶  특히 할당 목록 보기를 보고 관심 영역에서 어떤 개체가 지속되고 소멸되었는지 확인하고 싶습니다.

 

257. In the context of fragmentation, the destroyed objects create free memory slots, while the persisted objects are the remaining objects, responsible for keeping the pages dirty.

 ▶  조각화의 맥락에서, 파괴된 객체는 여유 메모리 슬롯을 생성하는 반면 지속된 객체는 페이지를 더티 상태로 유지하는 책임이 있는 나머지 객체입니다.

 

258. Both of them are worth investigating when you're looking into fragmentation.

 ▶  둘 다 조각화를 조사할 때 조사할 가치가 있습니다.

 

259. For more information about how to use the Instruments tool, check out the Getting started with Instruments talk from WWDC 2019.

 ▶  악기 도구 사용법에 대한 자세한 내용은 WWDC 2019의 악기 시작하기 강연을 확인하세요..

 

260. Now that I've addressed the leaks and heap regressions and verified that fragmentation isn't an issue, I'll run that XCTest again.

 ▶  이제 누수 및 힙 회귀를 해결하고 조각화가 문제가 아님을 확인했으므로 해당 XCTest를 다시 실행하겠습니다.

 

261. Excellent.

 ▶  훌륭한.

 

262. The XCTest now passes and the regression is resolved.

 ▶  이제 XCTest가 통과하고 회귀가 해결되었습니다.

 

263. Now that you've learned about detecting and diagnosing memory issues, let's review the workflow you can use for your own app.

 ▶  메모리 문제 감지 및 진단에 대해 배웠으므로 이제 자체 앱에 사용할 수 있는 워크플로를 검토해 보겠습니다.

 

264. Anytime you add a new feature, write a performance XCTest to monitor memory, and/or any of the other provided system metrics.

 ▶  새 기능을 추가할 때마다 성능 XCTest를 작성하여 메모리 및/또는 제공된 기타 시스템 메트릭을 모니터링하십시오.

 

265. For each test, set a baseline.

 ▶  각 테스트에 대해 기준선을 설정합니다.

 

266. Then use the test to catch regressions and investigate using the collected ktrace and memgraph files.

 ▶  그런 다음 테스트를 사용하여 회귀를 포착하고 수집된 ktrace 및 memgraph 파일을 사용하여 조사합니다.

 

267. Use the memgraphs from any failing XCTests to help diagnose your memory issue.

 ▶  실패한 XCTest의 memgraph를 사용하여 메모리 문제를 진단하십시오.

 

268. The first thing you should do is check for leaks.

 ▶  가장 먼저 해야 할 일은 누출 여부를 확인하는 것입니다.

 

269. Run the leaks tool and use the MSL backtraces to help find and fix any leaks.

 ▶  누출 도구를 실행하고 MSL 역추적을 사용하여 누출을 찾고 수정하십시오.

 

270. If the regression doesn't include leaks, then check out the heap.

 ▶  회귀에 누수가 포함되지 않은 경우, 힙을 확인하십시오.

 

271. Start with vmmap -summary to confirm that the memory is in the heap.

 ▶  vmmap -summary로 시작하여 메모리가 힙에 있는지 확인합니다.

 

272. If so, run heap -diffFrom to see which object types are responsible for the growth.

 ▶  그렇다면 heap -diffFrom을 실행하여 증가에 대한 책임이 있는 객체 유형을 확인하십시오.

 

273. If the culprits seem obvious, use heap -addresses to get their addresses.

 ▶  범인이 분명해 보이면 heap -addresses를 사용하여 주소를 가져옵니다.

 

274. If not, look at leaks -referenceTree for some clues.

 ▶  그렇지 않은 경우 몇 가지 단서를 위해 leaks -referenceTree를 살펴보십시오.

 

275. Finally, investigate culprit object addresses with leaks -traceTree and/or malloc_history.

 ▶  마지막으로, 누출 -traceTree 및/또는 malloc_history를 사용하여 범인 개체 주소를 조사하십시오.

 

276. Lastly, make sure you're developing with these memory best practices in mind.

 ▶  마지막으로, 이러한 메모리 모범 사례를 염두에 두고 개발하고 있는지 확인하십시오.

 

277. Strive to have zero leaks in your app.

 ▶  앱에서 누수가 발생하지 않도록 노력하십시오.

 

278. If you're working with unsafe types, make sure you remember to free everything you allocate.

 ▶  안전하지 않은 유형으로 작업하는 경우 할당한 모든 것을 해제해야 합니다.

 

279. And be on the lookout for retain cycles in your code as well.

 ▶  또한 코드에서 유지 주기를 살펴보십시오.

 

280. Find ways to reduce your heap allocations, whether that's shrinking them, holding them for a shorter period of time, or just getting rid of unnecessary allocations altogether.

 ▶  축소하거나, 더 짧은 기간 동안 유지하거나, 불필요한 할당을 완전히 제거하는 등 힙 할당을 줄이는 방법을 찾으십시오.

 

281. Make sure to keep fragmentation in mind.

 ▶  단편화를 염두에 두십시오.

 

282. Allocate objects with similar lifetimes next to each other to create nice, large chunks of free memory later on.

 ▶  비슷한 수명을 가진 객체를 서로 옆에 할당하여 나중에 훌륭하고 큰 여유 메모리 덩어리를 만듭니다.

 

283. With these best practices and the XCTest workflow, you'll be equipped to detect, diagnose, and fix memory issues in your app.

 ▶  이러한 모범 사례와 XCTest 워크플로를 통해 앱의 메모리 문제를 감지, 진단 및 수정할 수 있습니다.

 

284. On behalf of Tanuja and myself, thanks so much for tuning in.

 ▶  타누자와 저를 대신하여, 시청해주셔서 감사합니다..

 


출처

 

Detect and diagnose memory issues - WWDC21 - Videos - Apple Developer

Discover how you can understand and diagnose memory performance problems with Xcode. We'll take you through the latest updates to Xcode's...

developer.apple.com

댓글