问题1:通常一个手机会为一个app分配多大内存,如果不释放资源,一部手机加载多少张图片会产生oom
问题2:bitmap所占内存跟什么因素有关
问题3:怎么监测android内存变化情况
对几部手机进行了测试
int maxMemory = (int) Runtime.getRuntime().maxMemory();
Log.i(LOGTAG,"机型:" + android.os.Build.MODEL +" 可获取应用程序最大可用内存为:" + maxMemory);
结果如下:
01-20 18:21:43.782 30377-30377/com.blogxuan.oomdemo D/OOMDEMO: 机型:Nexus 4 可获取应用程序最大可用内存为:201326592
01-20 18:30:09.974 13471-13471/com.blogxuan.oomdemo I/OOMDEMO: 机型:DLI-AL10 可获取应用程序最大可用内存为:402653184
01-20 18:32:01.154 14823-14823/com.blogxuan.oomdemo I/OOMDEMO: 机型:MHA-AL00 可获取应用程序最大可用内存为:402653184
对一张3M的图片b1进行质量压缩得到157k的图片b2,转成bitmap后可看出占用内存并没变小
01-20 19:26:02.154 5114-5114/com.blogxuan.oomdemo I/OOMDEMO: b1.jpg图片实际大小: 3375228
01-20 19:26:02.154 5114-5114/com.blogxuan.oomdemo I/OOMDEMO: b1.jpgbitmap.getHeight(): 3000
01-20 19:26:02.154 5114-5114/com.blogxuan.oomdemo I/OOMDEMO: b1.jpgbitmap.getWidth(): 2000
01-20 19:26:02.154 5114-5114/com.blogxuan.oomdemo I/OOMDEMO: b1.jpgbitmap.getByteCount(): 12000000
01-20 19:26:02.154 5114-5114/com.blogxuan.oomdemo I/OOMDEMO: b1.jpgbitmap.getAllocationByteCount(): 12000000
01-20 19:26:02.154 5114-5114/com.blogxuan.oomdemo I/OOMDEMO: b1.jpgbitmap.getRowBytes(): 4000
01-20 19:26:02.154 5114-5114/com.blogxuan.oomdemo I/OOMDEMO: b1.jpgbitmap.getConfig(): ARGB_4444
01-20 19:26:02.155 5114-5114/com.blogxuan.oomdemo I/OOMDEMO: --------------------
01-20 19:26:02.401 5114-5114/com.blogxuan.oomdemo I/OOMDEMO: b2.jpg图片实际大小: 157124
01-20 19:26:02.401 5114-5114/com.blogxuan.oomdemo I/OOMDEMO: b2.jpgbitmap.getHeight(): 3000
01-20 19:26:02.401 5114-5114/com.blogxuan.oomdemo I/OOMDEMO: b2.jpgbitmap.getWidth(): 2000
01-20 19:26:02.401 5114-5114/com.blogxuan.oomdemo I/OOMDEMO: b2.jpgbitmap.getByteCount(): 12000000
01-20 19:26:02.401 5114-5114/com.blogxuan.oomdemo I/OOMDEMO: b2.jpgbitmap.getAllocationByteCount(): 12000000
01-20 19:26:02.401 5114-5114/com.blogxuan.oomdemo I/OOMDEMO: b2.jpgbitmap.getRowBytes(): 4000
01-20 19:26:02.401 5114-5114/com.blogxuan.oomdemo I/OOMDEMO: b2.jpgbitmap.getConfig(): ARGB_4444
01-20 19:26:02.401 5114-5114/com.blogxuan.oomdemo I/OOMDEMO: --------------------
加载不同长宽的图片
01-20 19:12:20.510 2500-2500/com.blogxuan.oomdemo I/OOMDEMO: b3.jpg图片实际大小: 51503
01-20 19:12:20.510 2500-2500/com.blogxuan.oomdemo I/OOMDEMO: b3.jpgbitmap.getHeight(): 1000
01-20 19:12:20.510 2500-2500/com.blogxuan.oomdemo I/OOMDEMO: b3.jpgbitmap.getWidth(): 1000
01-20 19:12:20.510 2500-2500/com.blogxuan.oomdemo I/OOMDEMO: b3.jpgbitmap.getByteCount(): 4000000
01-20 19:12:20.510 2500-2500/com.blogxuan.oomdemo I/OOMDEMO: b3.jpgbitmap.getAllocationByteCount(): 4000000
01-20 19:12:20.510 2500-2500/com.blogxuan.oomdemo I/OOMDEMO: b3.jpgbitmap.getRowBytes(): 4000
01-20 19:12:20.511 2500-2500/com.blogxuan.oomdemo I/OOMDEMO: b3.jpgbitmap.getConfig(): ARGB_8888
01-20 19:12:20.511 2500-2500/com.blogxuan.oomdemo I/OOMDEMO: --------------------
01-20 19:12:20.513 2500-2500/com.blogxuan.oomdemo I/OOMDEMO: b4.jpg图片实际大小: 17245
01-20 19:12:20.513 2500-2500/com.blogxuan.oomdemo I/OOMDEMO: b4.jpgbitmap.getHeight(): 100
01-20 19:12:20.513 2500-2500/com.blogxuan.oomdemo I/OOMDEMO: b4.jpgbitmap.getWidth(): 100
01-20 19:12:20.513 2500-2500/com.blogxuan.oomdemo I/OOMDEMO: b4.jpgbitmap.getByteCount(): 40000
01-20 19:12:20.513 2500-2500/com.blogxuan.oomdemo I/OOMDEMO: b4.jpgbitmap.getAllocationByteCount(): 40000
01-20 19:12:20.513 2500-2500/com.blogxuan.oomdemo I/OOMDEMO: b4.jpgbitmap.getRowBytes(): 400
01-20 19:12:20.513 2500-2500/com.blogxuan.oomdemo I/OOMDEMO: b4.jpgbitmap.getConfig(): ARGB_8888
01-20 19:12:20.513 2500-2500/com.blogxuan.oomdemo I/OOMDEMO: --------------------
修改色彩模式
01-20 19:14:03.430 2976-2976/com.blogxuan.oomdemo I/OOMDEMO: b3.jpg图片实际大小: 51503
01-20 19:14:03.430 2976-2976/com.blogxuan.oomdemo I/OOMDEMO: b3.jpgbitmap.getHeight(): 1000
01-20 19:14:03.430 2976-2976/com.blogxuan.oomdemo I/OOMDEMO: b3.jpgbitmap.getWidth(): 1000
01-20 19:14:03.430 2976-2976/com.blogxuan.oomdemo I/OOMDEMO: b3.jpgbitmap.getByteCount(): 2000000
01-20 19:14:03.430 2976-2976/com.blogxuan.oomdemo I/OOMDEMO: b3.jpgbitmap.getAllocationByteCount(): 2000000
01-20 19:14:03.430 2976-2976/com.blogxuan.oomdemo I/OOMDEMO: b3.jpgbitmap.getRowBytes(): 2000
01-20 19:14:03.430 2976-2976/com.blogxuan.oomdemo I/OOMDEMO: b3.jpgbitmap.getConfig(): ARGB_4444
01-20 19:14:03.430 2976-2976/com.blogxuan.oomdemo I/OOMDEMO: --------------------
01-20 19:14:03.433 2976-2976/com.blogxuan.oomdemo I/OOMDEMO: b4.jpg图片实际大小: 17245
01-20 19:14:03.433 2976-2976/com.blogxuan.oomdemo I/OOMDEMO: b4.jpgbitmap.getHeight(): 100
01-20 19:14:03.433 2976-2976/com.blogxuan.oomdemo I/OOMDEMO: b4.jpgbitmap.getWidth(): 100
01-20 19:14:03.433 2976-2976/com.blogxuan.oomdemo I/OOMDEMO: b4.jpgbitmap.getByteCount(): 20000
01-20 19:14:03.433 2976-2976/com.blogxuan.oomdemo I/OOMDEMO: b4.jpgbitmap.getAllocationByteCount(): 20000
01-20 19:14:03.433 2976-2976/com.blogxuan.oomdemo I/OOMDEMO: b4.jpgbitmap.getRowBytes(): 200
01-20 19:14:03.433 2976-2976/com.blogxuan.oomdemo I/OOMDEMO: b4.jpgbitmap.getConfig(): ARGB_4444
01-20 19:14:03.433 2976-2976/com.blogxuan.oomdemo I/OOMDEMO: --------------------
从结论可以看出,修改bitmap的宽高或者色彩模式可以减少内存占用
压力测试,机型nexus4,使用Android Studio的Android Profiler()观察app的内存变化,从之前结论可知允许内存占用为201M,一张5000*5000分辨率,色彩模式为ARGB_4444的图内存占用为50M(如果色彩模式为ARGB_8888,则占用内存为100M),猜想大概加载4张图片即可产生oom,
下图为验证结果(图片看不清可在新窗口打开):
app刚开始运行时内存为18m左右,当添加占用内存大小为50M的图片b6后,app内存为66M,添加同样大小的b7后内存为114M,添加b8后为161M,当试图添加b9时产生的oom:
01-21 12:41:15.156 7389-7389/com.blogxuan.oomdemo E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.blogxuan.oomdemo, PID: 7389
Theme: themes:{}
java.lang.OutOfMemoryError: Failed to allocate a 50000012 byte allocation with 16777216 free bytes and 43MB until OOM
at dalvik.system.VMRuntime.newNonMovableArray(Native Method)
at android.graphics.BitmapFactory.nativeDecodeAsset(Native Method)
at android.graphics.BitmapFactory.decodeStream(BitmapFactory.java:609)
at com.blogxuan.oomdemo.PhotoWallAdapter.notifyDataSetChanged(PhotoWallAdapter.java:170)
at com.blogxuan.oomdemo.MainActivity$1.onClick(MainActivity.java:69)
at android.view.View.performClick(View.java)
at android.view.View$PerformClick.run(View.java:21158)
at android.os.Handler.handleCallback(Handler.java:739)
at android.os.Handler.dispatchMessage(Handler.java:95)
at android.os.Looper.loop(Looper.java:148)
at android.app.ActivityThread.main(ActivityThread.java:5461)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:726)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:616)
01-21 12:41:15.158 682-694/system_process W/ActivityManager: Force finishing activity com.blogxuan.oomdemo/.MainActivity
后面也尝试了把图片色彩模式修改ARGB_8888,添加了第二张100M的图片时即产生了崩溃。
用华为mate9进行了测试(图片看不清可在新窗口打开)
虽然日志中显示mate9可用最大内存为400M,但是在测试过程中添加了5张100M的图片,app居然没崩,而且从Android Profiler也看到内存最大时甚至超过了1G,可见mate9确实对内存这一块进行了优化,后面也对荣耀6a这款同样显示可用最大内存为400M的机型进行了测试,不出意外加载了第四张100M的图片时oom了。
问题1:见上述实验结果
问题2:跟bitmap的宽,高,以及色彩模式
问题3:使用android studio的Android Profiler