Android 圖片資源的目錄 -- 一個背景圖片引發的內存 OOM

在開發中應用突然crash, 從日志上看是解壓圖片內存不足導致發生了OOM。

Caused by: java.lang.OutOfMemoryError: Failed to allocate a 85881612 byte allocation with 16777216 free bytes and 69MB until OOM

用Android monitor 看了下內存,打開這個Activity時,內存直接跳漲了60M左右。好崩潰。

oom_oom.png

看了下這個Activity有一個背景,背景為png圖片。注釋掉這個背景圖片后,從Android Monitor 上看內存的曲線平滑了。原因就是這張圖片了。但是一張圖片也不能吃掉60M的內存。

res/mipmap/pc_car.png: PNG image data, 1440 x 1217, 8-bit/color RGBA, non-interlaced

分辨率大小為 1440x1217, 32為像素,解壓后大小應該為6M, 還是不能解釋上面的原因。

用Android Motinor 把內存dump 出來。

oom_monitor_bitmap.png

這張bitmap 大小為85881640,大約為81M。然后看下分辨率

明顯被放大了。手機為 NEXUS 6P, 像素密度為XXXHDPI. 也就是說圖片被放大了3x3 9倍的大小。圖片原來放在了mipmap 目錄,作為HDPI的資源處理了, 手機需要XXX 的資源,然后被放大。圖片的位置不正確。

把圖片放到不同的目錄看下效果:

目錄 效果
drawable 圖片放大
mipmap 圖片放大
drawable-nodpi 正常
mipmap-nodpi 正常
drawable-xxxdpi 正常
mipmap-xxxdpi 正常

因此應當把背景圖片放到 drawable-nodpi

Bitmap heap

關于android bitmap 內存的分配,在Android 3.0 以前,內存被分配在了 Nativie 堆,3.0 以后被分配在了Java 堆。

dalvik.vm.heapstartsize

堆分配的初始大小,調整這個值會影響到應用的流暢性和整體ram消耗。這個值越小,系統ram消耗越慢,但是由于初始值較小,一些較大的應用需要擴張這個堆,從而引發gc和堆調整的策略,會應用反應更慢。相反,這個值越大系統ram消耗越快,但是程序更流暢。

dalvik.vm.heapgrowthlimit

 極限堆大小,dvm heap是可增長的,但是正常情況下dvm heap的大小是不會超過dalvik.vm.heapgrowthlimit的值。如果受控的應用dvm heap size超過該值,則將引發oom。

dalvik.vm.heapsize

使用大堆時,極限堆大小。一旦dalvik heap size超過這個值,直接引發oom。在android開發中,如果要使用大堆,需要在manifest中指定android:largeHeap為true。這樣dvm heap最大可達dalvik.vm.heapsize。

[dalvik.vm.heaptargetutilization]: [0.75]

可以設定內存利用率的百分比,當實際的利用率偏離這個百分比的時候,虛擬機會在GC的時候調整堆內存大小,讓實際占用率向個百分比靠攏。

mipmap 和 drawable 目錄

Google 為App 開發引入AndroiStudio 以后,用來放圖片的目錄多了一個mipmap 目錄。然后關于圖片到底是放在drawable 目錄還是mipmap 目錄就有了爭議。

Using a mipmap as the source for your bitmap or drawable is a simple way to provide a quality image and various image scales, which can be particularly useful if you expect your image to be scaled during an animation.

Android 4.2 (API level 17) added support for mipmaps in the Bitmap class—Android swaps the mip images in your Bitmap when you've supplied a mipmap source and have enabled setHasMipMap(). Now in Android 4.3, you can enable mipmaps for a BitmapDrawable object as well, by providing a mipmap asset and setting the android:mipMap attribute in a bitmap resource file or by calling hasMipMap().

您應該將所有啟動器圖標都置于 res/mipmap-[density]/ 文件夾而非 drawable/ 文件夾內,以確保啟動器應用使用最佳分辨率圖標。 如需了解有關使用 mipmap 文件夾的詳細信息,請參閱管理項目概覽。

從這段話來看,是App Icon 使用mipmap 目錄。其他資源繼續使用drawable 目錄。

在StackOver 上有一個解釋的比較好的答案:

mipmap-drawables-for-icons

大概意思是 Luncher APK 在顯示ICON 時選擇高分辨率的圖片。有時候為了減小APK 包的大小,APK 就只包含一種分辨率的圖片,這時Luncher 會放大圖片,圖片就會模糊了。

資源文件還是放在drawable 目錄。

BAT的APP

然后看下各大廠的App 是怎么放資源文件的。這幾個超級APP都沒有使用mipmap 文件夾。就是App 圖標也放在了drawable 目錄。

鵝廠的微信:

weixin.png

微信的背景圖只放在了drawable 和drawable-hdpi 目錄。 在hdpi 目錄單獨放可能是為了在低端機上適配,節約內存。 以ba.jpg 為例, 320x480 大小,解壓后為600K, 在XXXHDPI 手機上放大后為5.4M。

MBC02T6468G8WN:res louie.wang$ find . -name b*.jpg
./drawable/ba.jpg
./drawable/bb.jpg
./drawable/bd.jpg
./drawable/be.jpg
./drawable-hdpi-v4/bb.jpg
./drawable-hdpi-v4/bd.jpg
./drawable-hdpi-v4/be.jpg

./drawable/ba.jpg: JPEG image data, baseline, precision 8, 320x480, frames 3

鵝廠的QQ:

QQ.png

QQ 應該使用了插件開發,目錄比較簡單。手機QQ 在drawable 目錄下放了很多背景圖,圖片都不是太大,但是在高分辨率手機上肯定有內存的占用問題。而且QQ沒有提供 XXXHDPI 的資源。

手淘:

taobao.png

手淘也采用了插件開發,整個目錄清爽了很多。和QQ一樣,手淘在drawable 目錄放了很多背景圖片。沒有根據不同的分辨率單獨出圖。 值得注意的是手淘有一個 drawable-anydpi-v21 目錄

ls drawable-anydpi-v21/
design_ic_visibility_off.xml

MBC02T6468G8WN:res louie.wang$ find . -name design_ic_visibility_off.*
./drawable-anydpi-v21/design_ic_visibility_off.xml
./drawable-mdpi-v4/design_ic_visibility_off.png
./drawable-xhdpi-v4/design_ic_visibility_off.png
./drawable-xxhdpi-v4/design_ic_visibility_off.png
./drawable-xxxhdpi-v4/design_ic_visibility_off.png

手機百度:

baidu.png

手機百度 的drawable 目錄也放了20 張左右的背景圖片。但是手機百度有一個 drawable-nodpi
目錄。

ls drawable-nodpi-v4/
back_btn.png   bt_white.9.png    city_search_bg.9.png       titlebar_bg.9.png
bt_grey.9.png  bt_white_p.9.png  groupon_titlebar_bg.9.png  union_list_bg_middle.9.png

根據Google 的指引,

screens_support
nodpi 適用于所有密度的資源。這些是密度獨立的資源。不管當前屏幕的密度如何,系統都不會 縮放以此限定符標記的資源。

SVG 圖片

在手機淘寶的res 目錄下有一個 drawable-anydpi-v21 目錄,用來放在矢量圖片的。

Google 關于svg 和anydpi的解釋:

anydpi:此限定符適合所有屏幕密度,其優先級高于其他限定符。 這對于矢量可繪制對象很有用。 此項為 API 級別 21 中新增配置

Android 4.4(API 級別 20)及更低版本不支持矢量圖。如果最低 API 級別設置為上述 API 級別之一,則在使用 Vector Asset Studio 時您有兩個選擇:生成便攜式網絡圖形 (PNG) 文件(默認)或使用支持庫。為實現向后兼容性,Vector Asset Studio 會生成矢量圖的光柵圖像。矢量和光柵圖一起打包到 APK 中。您可以在 Java 代碼中以 Drawable 的形式引用矢量圖,或在 XML 代碼中以 @drawable 的形式引用矢量圖;當您的應用運行時,對應的矢量或光柵圖像會自動顯示,具體取決于 API 級別。

在淘寶的的drawable-anydpi 放了一張design_ic_visibility_off.xml 圖片,在drawable-* 目錄下都有對應的png 圖片。這是Android Studio 自動生成的。

進入自己的工程中找一張SVG 圖片看下,可以看到把SVG圖片放在了drawable 目錄,然后AS 自動的從drawable 目錄中把SVG圖片分離出來,放在了 drawable-anydpi-v21 目錄,同時在對應的drawable-**hdpi 目錄下生成png 圖片。

MBC02T6468G8WN:AndroidSample louie.wang$ find . -name ic_user.*
./app/build/generated/res/pngs/debug/drawable-anydpi-v21/ic_user.xml
./app/build/generated/res/pngs/debug/drawable-hdpi/ic_user.png
./app/build/generated/res/pngs/debug/drawable-ldpi/ic_user.png
./app/build/generated/res/pngs/debug/drawable-mdpi/ic_user.png
./app/build/generated/res/pngs/debug/drawable-xhdpi/ic_user.png
./app/build/generated/res/pngs/debug/drawable-xxhdpi/ic_user.png
./app/build/generated/res/pngs/debug/drawable-xxxhdpi/ic_user.png
./app/build/intermediates/res/merged/debug/drawable-anydpi-v21/ic_user.xml
./app/build/intermediates/res/merged/debug/drawable-hdpi/ic_user.png
./app/build/intermediates/res/merged/debug/drawable-ldpi/ic_user.png
./app/build/intermediates/res/merged/debug/drawable-mdpi/ic_user.png
./app/build/intermediates/res/merged/debug/drawable-xhdpi/ic_user.png
./app/build/intermediates/res/merged/debug/drawable-xxhdpi/ic_user.png
./app/build/intermediates/res/merged/debug/drawable-xxxhdpi/ic_user.png
./app/src/main/res/drawable/ic_user.xml

同樣把圖片放到 drawable-anydpi 目錄

MBC02T6468G8WN:AndroidSample louie.wang$ find . -name ic_user.*
./app/build/generated/res/pngs/debug/drawable-anydpi-v21/ic_user.xml
./app/build/generated/res/pngs/debug/drawable-hdpi/ic_user.png
./app/build/generated/res/pngs/debug/drawable-ldpi/ic_user.png
./app/build/generated/res/pngs/debug/drawable-mdpi/ic_user.png
./app/build/generated/res/pngs/debug/drawable-xhdpi/ic_user.png
./app/build/generated/res/pngs/debug/drawable-xxhdpi/ic_user.png
./app/build/generated/res/pngs/debug/drawable-xxxhdpi/ic_user.png
./app/build/intermediates/res/merged/debug/drawable-anydpi-v21/ic_user.xml
./app/build/intermediates/res/merged/debug/drawable-hdpi/ic_user.png
./app/build/intermediates/res/merged/debug/drawable-ldpi/ic_user.png
./app/build/intermediates/res/merged/debug/drawable-mdpi/ic_user.png
./app/build/intermediates/res/merged/debug/drawable-xhdpi/ic_user.png
./app/build/intermediates/res/merged/debug/drawable-xxhdpi/ic_user.png
./app/build/intermediates/res/merged/debug/drawable-xxxhdpi/ic_user.png
./app/src/main/res/drawable-anydpi/ic_user.xml

可以得出如下結論:

  1. App icon 放在mipmap-XXX 目錄。放在drawable-XXX 目錄也可以,只是某些情況下圖片沒那么清晰。
  2. 背景圖片資源 放在 drawable-nodpi 目錄。這樣避免自動放大圖片。
  3. 自定義的 drawable XML 放在 drawable 目錄
  4. SVG 文件可以放在drawable-anydpi 目錄,根據Google Doc, anydpi 后綴是特備為矢量圖準備的。
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 228,923評論 6 535
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 98,740評論 3 420
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 176,856評論 0 380
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,175評論 1 315
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 71,931評論 6 410
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,321評論 1 324
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,383評論 3 443
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,533評論 0 289
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 49,082評論 1 335
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 40,891評論 3 356
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 43,067評論 1 371
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,618評論 5 362
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,319評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,732評論 0 27
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,987評論 1 289
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,794評論 3 394
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 48,076評論 2 375

推薦閱讀更多精彩內容