檢測和診斷內存問題

性能是客戶端永恆的主題,咱們但願用戶在使用APP時,可以得到極致的性能體驗,關注內存佔用也正是由於這一點。git

(舒適提示:本片內容來源自WWDC21:Detect and diagnose memory issuesgithub

想了解更多WWDC2021內容的小夥伴,能夠閱讀我如下文章,歡迎多多交流和指正swift

一文帶你讀完WWDC21核心(新)技術點xcode

APP終極性能生存指南markdown

  • Faster application activationsapp

    減小APP的內存佔用,能夠提升APP在後臺存活的機會,從而讓APP更快的被激活。ide

    設備的內存空間是有限的,監控APP的內存使用狀況,可以防止系統爲了回收內存而主動終止APP。工具

    這樣即便APP在後臺運行,也可以保存當前用戶的使用狀態,從而避免再次從內存加載致使的耗時。oop

  • Responsive experiencepost

    更好的響應速度

    策略性的將APP的內容加載到內存裏,可以避免在用戶使用APP時,因系統回收內存增長的等待耗時。

  • Complex features

    讓用戶體驗更豐富的功能

    像加載視頻、展現動畫,這些複雜的功能每每須要佔用更多的內存。所以有策略的使用內存,能夠避免在用戶使用APP的複雜功能時,被系統因內存佔用問題而終止。

  • Wider device compatibility

    更好的設備兼容性

    讓內存空間不太充足的老設備也能更好的使用APP的功能

內存佔用結構

2.png

  • Clean Memory

  • Dirty Memory

    Clean Memory被分配,並寫入內容後成爲」髒內存「,髒內存包括:

    • 全部的堆分配(malloc)
    • 解碼圖像緩衝區
    • Frameworks
  • Compressed Memory

    壓縮內存特指髒頁(Dirty Pages)中暫未被訪問的部分(Unaccessed pages),會在訪問後解壓,成爲髒內存。

    (下文會詳細介紹髒頁(Dirty Pages)的概念)

    注:iOS中沒有內存交換(Memory Swap)的概念,你可能在使用Instrument工具時,見到過Swapped字段,實際上所指的是Compressed Memory

內存佔用 = Dirty Memory + Compressed Memory

內存畫像工具

3.png

  • XCTest

    經過單元測試和U測試中的XCTest來檢測開發環境的性能指標

    • XCTest能夠測量如下性能指標:

      • 內存使用狀況
      • CPU使用
      • 磁盤寫入狀況
      • 卡頓率
      • 執行時間(完成某一任務所花的所有時間)
      • APP啓動時間
    • 經過XCTest檢測內存使用狀況

      func testSaveMeal() {
      	let app = XCUIApplication()
      	let options = XCTMeasuireOptions()
      	options.invocationOptions = [.manullyStart]
      	measure(metrics: [XCTMemoryMetric(application: app)],
      					options:options) {
      		app.launch()
      		startMeasureing()
      		app.cells.firstMatch.buttons["Save meal"].firstMatch.tap()
      		
      		let savedButton = app.cells.firstMatch.buttons["Saved"].firstMatch
      		XCTAssertTure(savedButton.waitForExistence(timeout: 30))
      	}
      }
      複製代碼
    • XCTest在Xcode 13中新增的兩項收集性能狀況的診斷產物

      開啓:enablePerformanceTestsDiagnostics YES

      xcodebuild test
      -project MealPannerApp.xcodeproj
      -scheme PerformanceTests
      -destination platform=iOS,name="iPhone"
      -enablePerformanceTestsDiagnostics YES
      複製代碼
      • Ktrace files

        Ktrace file可以打開,並展現如下分析報告:

        • 當卡頓發生時的渲染通道的狀態
        • 因主線程阻塞,致使的Hang(APP沒法響應用戶的輸入或者行爲超過250ms,即記做一個hang)
      • Memory graphs

        Memory graph展現APP進程的地址空間的快照

        咱們能夠生成任務開始(pre_XXX.memgraph)和結束(post_XXX.memgraph)兩個時機的內存快照,從而查看這一階段內存佔用的變化。

        4.png

  • MetricKit & Xcode Organizer

    檢測線上環境的內存指標

內存問題

  • 內存泄漏(Leaks)

    最多見內存泄漏的緣由的是循環引用

    5.png

    • 經過命令行查看memgraph文件

      6.png

  • 堆大小問題(Heap size issues)

    堆是進程地址空間中儲存動態分配的對象的段(section),有策略性的加載和釋放內存,能夠避免內存峯值太高引起OOM。

    • 堆分配迴歸(Heap allocation regressions)
    • 碎片化(Fragmentation)

堆分配迴歸

  • 使用vmmap -summary對memgraph文件進行分析

7.png

  • 咱們主要關心Dirty SizeSwapped Size兩列數據

    8.png

  • 對任務開始(pre_XXX.memgraph)和結束(post_XXX.memgraph)兩個時機的內存快照進行對比

    9.png

  • 能夠在下方看到按類聚合的,各種對象佔用內存的大小

    10.png

    從圖中能夠看到,non-object類型的數據,佔用內存約13M。在Swift中,non-object一般表明原始分配字節(raw malloced bytes)

  • 打印memgraph文件中,類型爲non-object且佔用內存超過500k的對象

    11.png

  • 打印對象的引用樹

    12.png

  • 能夠經過malloc_history -fullStacks打印對象的分配調用棧

    13.png

  • 當不肯定是哪一個對象有問題時,能夠經過leaks --referenceTree,自頂向下打印進程的全部內存中最可疑的對象

    14.png

    • 能夠經過--groupByType參數,按type聚合簡化打印結果。

    15.png

碎片化

先介紹兩個概念:頁和」髒頁「

  • 頁(Pages):是最小的獨立的內存單元
  • 一旦頁中寫入任何數據,都會使整頁變成」髒頁「

16.png

當內存準備寫入新的數據時,系統會優先嚐試使用髒頁中的空閒內存,而立即將分配的內存過大時,即便空閒內存的總大小足夠,但其並非一段連續的內存空間,仍會開闢一個新的髒頁去寫入這些數據。

這些沒法被使用的空閒內存就是」碎片化內存「

再例如如下這種狀況:咱們分配的對象總共使用了4個頁,但每一個頁的佔用空間只佔50%。

25.png

當咱們釋放這些對象後,這些4個髒頁的內存空間仍有50%的碎片化內存。

最理想化的狀態應該將全部的分配的對象放在兩頁,以下圖:

18.png

這樣一旦釋放這些對象時,僅會留有兩個髒頁,而且不存在碎片化內存。

19.png

  • 咱們的目標:

    • 讓分配的對象儘量連續且擁有一樣的生命週期
    • 碎片化率保持在25%如下
    • 使用自動釋放池
    • 特別注意長時間運行的進程
  • vmmap -summary xx.memgraph查看碎片化內存狀況

    20.png

    • DefaultMallocZone

      平時開發者只須要關注這部分的內存空間,由於這是咱們進行堆分配默認結束的地方

    • MallocStackLoggingLiteZone

      這個空間是全部堆分配結束的地方

  • 使用Instruments工具中的Allocations track查看內存狀況

    21.png

    其中的Destroyed和Persisted分別對應上面所描述的內存釋放後的空閒內存(free memory)和仍未釋放的內存(remaining objects)

    22.png

回顧下咱們的整體排查流程:

23.png

更多WWDC有關性能的Session

iOS memory deep dive WWDC18

Getting started with Instruments WWDC19

Understand and eliminate hangs from your apps WWDC21

相關文章
相關標籤/搜索