天天看點

React Native Android 應用記憶體使用探究

<b>本文講的是React Native Android 應用記憶體使用探究,</b>

剛開始接觸 React Native 應用時,我發現有個現象很奇怪,在 Android 手機上我無法看到任何圖檔,隻有顔色和文字可以顯示。但 iOS 手機卻沒有任何問題。

我以為是我新找來測試 React Native 工程的 Android 手機有問題。我甚至被這錯誤的想法牽着刷了 rom (基于 AOSP 5.1.1 的系統)來在更高的 Android 版本上運作 React Native,當然也有着避免被 Samsung 自帶應用影響的原因。然而,除了樣例工程的首屏外,其他地方仍看不到圖檔。于是我将這手機打入冷宮。

幾天後,我的朋友指出 React Native 的 Android 應用在一些特定螢幕上無法加載圖檔。呃……這可真夠奇怪的……等等,我好像在哪兒見過這現象……

好吧,原來不止是我的手機有這現象。

代碼很明了,在顯示圖檔方面并沒有用什麼黑科技或者第三方庫。我開始在不同Android版本的 GenyMotion 和 Android Virtual Device ( AVD ,Android 虛拟機)上運作(React Native應用)。

  我的手機:隻能在第一屏看到圖檔

  GenyMotion (API 21, API 22):部分節點有問題

  AVD (API 21, API 22, API 23):完全沒問題?!

我本以為這是在特定機型或者 API 版本上發生的事情,但顯然不是這樣的。也就是說我需要考慮一堆其他的可能性。這可真讓人頭痛。

這應用有許多作為背景顯示的圖檔,而且這些圖檔也不算小(400~800 kb)。除此之外,雖然不太可能,但仍有點可疑的是,這些圖檔都是通過遠端 URI 擷取的。

我開始對記憶體結構産生了好奇心,尤其是從遠端加載圖檔時動态配置設定的堆空間。于是我開始追蹤記憶體使用。

幾年前,我用這個來檢視記憶體:

我喜歡指令行應用,但當涉及到圖形化的記憶體使用時,這真的不是什麼界面友好的東西。

React Native Android 應用記憶體使用探究

别告訴我你喜歡看這樣的記憶體分享界面。

React Native Android 應用記憶體使用探究

最容易擷取(并且免費!)的記憶體檢視器就是 Android Device Monitor。如果你安裝過 Android Studio 的話,你就已經擁有它了。按照如下步驟來打開它:

用平常的方式運作 React Native 應用 (react-native run-android)

運作 Android Studio

在菜單欄找到并打開 Tools → Android → Enable ADB Integration

點選 Tools → Android → Android Device Monitor

當顯示 Android Device Monitor 界面時,點選 Monitor → Preferences

在打開的對話框中找到 Android → DDMS ,選中這兩項

  Heap updates enabled by default(預設更新堆開啟)

  Thread updates enable by default (optional)(預設更新線程開啟)

React Native Android 應用記憶體使用探究

之後你就會看到一個如圖所示的界面 (System Information tab):

React Native Android 應用記憶體使用探究

如果你看到這個界面的話:

React Native Android 應用記憶體使用探究

執行下面這條指令來確定你的開發服務連上了裝置。

當你從 Android Studio 運作一個已經通過 react-native run-android 啟動的應用時,可能發生這個問題。

React Native Android 應用記憶體使用探究

在左邊的 Devices 欄選擇你的應用。現在記憶體檢查前的工作就已經準備完畢了。

當我運作 Android Device Monitor 并來回拖動時,我發現了一些奇怪的現象。

React Native Android 應用記憶體使用探究

即使第一屏使用的記憶體已經在124MB左右時,堆大小也并沒有明顯超過124MB的迹象。但垃圾回收卻開始執行:

于是問題來了, “為什麼堆的記憶體如此小?”

Android 5.0.0 中 ART Java Heap Parameter 推薦的 dalvik.vm.heapsize 值為 384MB:

React Native Android 應用記憶體使用探究

我甚至去拉了我手機的 build property 檔案 (adb -d pull /system/build.prop) 然後證明堆記憶體是 256 MB.

React Native Android 應用記憶體使用探究

後來我知道怎麼設定大記憶體了,隻需在 AndroidManifest.xml 中加這行代碼:

這是我開啟 largeHeap 後的結果:

React Native Android 應用記憶體使用探究

就是這樣。是的,就這麼一行該死的代碼。真是夠惡心的!

所有 AVD 裝置( API 21 ~ 23)在顯示圖檔時沒有這個問題的原因是模拟器更智能。當需要時它會增大堆的大小,雖然設定堆大小(的行為)會産生警告。

确切地說,我在上文解決的問題并不算是一個應用記憶體問題,而是設定問題。如果你的應用有隐藏更深的記憶體問題,使用基于 Eclipse RCP 的 Memory Analyzer 來檢查是否有記憶體洩漏是一種可行的方法。

點選 Cause GC 來執行垃圾回收。

React Native Android 應用記憶體使用探究

2. 點選 Dump HPROF file 按鈕來捕獲記憶體轉儲檔案。

React Native Android 應用記憶體使用探究

3. 将 Android 轉儲檔案轉換成 Memory Analyzer 可以讀取的格式。 (你需要 Android SDK的 platform-tools )

4. 運作 Memory Analyzer 打開轉換後的 hprof 檔案。然後選擇 Leak Suspects Report (你可以先點取消,稍後再執行)。

React Native Android 應用記憶體使用探究

5. 就是這樣,喵~

React Native Android 應用記憶體使用探究

假設你的 React Native 應用有個 Android 原生的子產品。子產品中有個單例類會在調用 listener 的 onUpdate() 函數時建立一個包含 10,000,000 個元素的 String 數組。(我知道這是個無意義類,但我們先關注主要沖突吧。簡單點。)

悲劇的是,你忘記在 onDestroy() 中取消監聽了,這就會在每次旋轉螢幕時導緻記憶體洩漏。你就會奇怪為什麼應用莫名其妙的崩潰了。

以下是 Memory Analyzer 在執行完上述 5 步的界面:

React Native Android 應用記憶體使用探究

如圖所示, LetsLeak 類占用了相當多的記憶體。注意這隻是個假設而不是實際情況。

讓我們聚焦于 Dominator Tree 。

React Native Android 應用記憶體使用探究

你可以在 Top Consumers 看到排序後的記憶體使用清單,但是如果是這種隻有一個疑點需要仔細排查的情況, Dominator Tree 是個更好的選擇。

React Native Android 應用記憶體使用探究

在 Dominator Tree 界面, Shallow Heap 是記憶體引用的意思, Retained Heap 則代表所有類實際持有的記憶體。

在 Inspector 界面,你可以看到你建立的超大數組。你也許會想,**“我是在單例裡建立了一個 String 數組,但為什麼會持有這麼大的記憶體?應該隻有一個才對……”**之後你會意識到自己并沒有釋放記憶體,這是使用單例時的常見問題。

将 Android Device Monitor 和 Memory Analyzer 高效地結合起來可以監視線程并且可以通過轉儲記憶體查找所有 Android 系統上的記憶體問題。 Android 上的 React Native 也不例外。

就像上文舉例的記憶體洩漏問題一樣,一個簡單對象持有你想不到的大記憶體這種情況是很容易找到原因的。然而在開發環境中追蹤記憶體洩漏還是相當困難的。毋庸置疑的是,這些工具可以帶來極大的便利。

<b></b>

<b>原文釋出時間為:2016年11月22日</b>

<b>本文來自雲栖社群合作夥伴掘金,了解相關資訊可以關注掘金網站。</b>

繼續閱讀