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阅读 216,163评论 6 498
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,301评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 162,089评论 0 352
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,093评论 1 292
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,110评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,079评论 1 295
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,005评论 3 417
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,840评论 0 273
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,278评论 1 310
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,497评论 2 332
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,667评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,394评论 5 343
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,980评论 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,628评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,796评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,649评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,548评论 2 352

推荐阅读更多精彩内容