1. 程式人生 > >記一次詭異的OOM坑

記一次詭異的OOM坑

OOM,即OutOfMemory。作為Android裝置常見的效能問題,經常見於圖片大量載入的場景。然而博主這次碰到的OOM,卻是由一個意想不到又合情合理的問題導致。由於是半路接手一個正在開發的專案,著實被坑了一把。

一. 場景描述:

  1. 在一個Activity中,會非同步生成一張二維碼圖片。不過這個功能顯然是後來匆忙加的,因為二維碼Bitmap並沒有快取(專案其它地方的圖片都是用Glide)。這樣導致每次進入Activity,都會重新建立一個Bitmap。

    image

  2. 在使用App較長時間後,再次進入這個Activity偶爾會導致OOM。

二. 嘗試解決

  1. 這個二維碼Bitmap,畫素為700*700.我們嘗試使用Glide載入到ImageView中,這樣只會在第一次進入Activity時,才會通過ZXing建立二維碼Bitmap。

    不過在經過測試之後,仍然會出現OOM。我們開啟Android Profiler,來監測記憶體情況:

    image

  2. 對比進入Activity前後的記憶體佔用情況:

    image

    image

    Graphics的記憶體佔用突然增長了51M。

    而且是每次進入Activity,都會發生如此劇烈的抖動,除了二維碼圖片,還有其它的問題。

  3. 註釋掉二維碼圖片的生成,然後再次觀察測試。情況依舊,記憶體佔用峰值瞬時增加50-100M:

    image

三. 大家來找茬

  1. 疑點:

    在有點懵圈的時刻,不經意間瞟了一眼介面,發現了可疑之處:

    image

    開始看見這塊白色背景時,還以為是設定了color;

    切到相關佈局xml一看:

    android:background="@drawable
    /layout_bg"

    很好,去目錄下看看這張圖:

    image

    簡直嚇死寶寶了,一張1034*1398的無碼高清PNG大圖…..

  2. 再次嘗試:

    android:background="#ffffff"

    順滑多了:

    image

    至此問題解決,罪魁禍首就是那一張高解析度無碼高清大圖。

四. 小結

  1. Android Profiler是好工具。
  2. 任何圖片的載入,都會出現增加記憶體開銷。圖片快取的意義也就在於此—–通過快取策略控制圖片的記憶體消耗。然而直接在XML中設定載入圖片,就沒辦法使用快取了。
  3. 本來這個問題應該很容易發現的,但半路接手專案,還不太熟悉,以至於走了彎路。當然,那張二維碼圖片仍然是應當快取起來的。
  4. 要跟產品、美工溝通好,這種神奇的背景圖片就不應當用,它會拖慢載入速度,增加記憶體壓力。而且還有更好的處理方式。比如9Patch,VectorDrawable,等等。