Android統計方法耗時之:內存控制

鴿了好久, 如今補上緩存


上篇提到, 作好方法堆棧的收集後, 項目工程運行不到兩分鐘, 出先卡頓, 直至完全卡死.markdown

經過Android Studio Profile調查得知, 正是我統計耗時的MethodNode堆棧撐爆了內存.app

爲了監控方法耗時, 可是居然搞出了內存問題, 有些搞頭..spa

緣由調查

由於每一個方法都被插樁, 因此每一個方法的先後調用關係都作成MethodNode被存到了堆棧中,設計

因此隨着使用時間的增加, 全部方法關係都存進了堆棧中, 不被清理, 就撐爆了內存.code

設計方案

這個問題其實是個OOM問題. OOM從技術角度看, 是由於改釋放的內存不被釋放.orm

可是要解決OOM問題, 卻須要從具體業務入手, 由於只有經過業務關係梳理, 才知道那些內存應該釋放.對象

針對此次的問題, 就是要減小方法關係的存儲.內存

因此作以下設計:

  1. 過濾掉重複的方法調用關係MethodNode. 只保存精簡方法關係堆棧
  2. 製做MethodNode緩存池, 建立MethodNode時, 優先從緩存池中獲取. 獲取失敗再建立
  3. 每一個被配斷定爲重複的方法對象MethodNode, 存入緩存池等待複用
方案設計好, 又面臨以下問題:
  1. 如何判斷"重複的調用關係"?
  2. 緩存池要頻繁讀寫, 如何設計避免讀寫衝突?

1. 重複調用關係判斷

由於MethodNode中保存了父節點和子節點信息. 因此當獲得一個新MethodNode時,開發

獲取它的父節點信息, 再從現有的堆棧中, 找到對應的父節點,

查看該父節點中的全部子節點是否已經包含那個新MethodNode的信息.

若是包含, 說明重複, 則丟棄這個新MethodNode. 若是不包含, 就把新MethodNode加入堆棧裏父節點的子節點列表裏,

若是沒有找到父節點, 則這個新MethodNode直接當作root級別父節點, 存入堆棧

2. 緩存池設計

聊這個, 我可就不困了.

特別爲這個設計裏一個存取交換池.

簡單的說, 設計了兩個緩存池, 某個時間段內, 一個池只取, 另外一個池只存.

當"只取"的池子空了, 就切換成"只存"狀態. 同時, 以前"只存"的池子同步切換爲"只取"

這樣兩個池子, 交替使用

若是兩個坑都沒有磚, 我就去找磚廠要磚. 回收的磚一樣按照輪換扔到當前應該回收轉的坑裏.

至關於作到存取隔離, 也就沒有了存取衝突. 同時有複用機制. 內存的數量不會激增.

過程大體以下:

結果驗證

按照設計, 開發完畢實測.

緩存池初期不斷增大, 2w個以後逐漸穩定.再也不增加.

知足了整個app的循環複用. 內存問題解決.

相關文章
相關標籤/搜索