【Android】安卓常见的内存泄漏:OOM,bitmap
一、关于OOM
1. android图片加载导致的OOM分析及有效解决办法(BitmapUtils)
[摘] OOM原因分析
android每一个应用都有一个独立的进程,每个进程都是实例化了dalvik虚拟机实例的linux进程。Dalvik 主要管理的内存有 Java heap 和 native heap 两大块。Android系统对dalvik的vm heapsize作了硬性限制,当java进程申请的java空间超过阈值时,就会抛出OOM异常(这个阈值可以是48M、24M、16M等,视机型而定),而native heap大小则是不受次限制的。
当我们需要显示大的bitmap对象或者较多的bitmap的时候,如果使用setImageBitmap或setImageResource或BitmapFactory.decodeResource来设置图片,则容易出现OOM,这个是因为bitpmap分配内存受限于java heap大小(一张在1024*1024图片,假设照片是用ARGB_8888格式,那么需要占用4M的内存存储像素点信息, bitmap分辨率越高,所占用的内存就越大,这个是以2为指数级增长的。)。此处引出一个问题:bitmap对象是分配在native heap还是java heap上的呢?后续会在单独一篇文章中讲解(Bitmap分配在java heap还是native heap)
2. android Bitmap分配在java heap还是native heap
在android 2.3和以前的版本,bitmap对象的像素数据都是分配在native heap中的,所以我们在调试过程中这部分内存是在java heap中看不到的,不过在android 3.0之后,bitmap对象就直接分配在java heap上了,这样便于调试和管理。因此在3.0之后我们可以复用bitmap的内存,而不必回收它,不过新的bitmap对象要大小和原来的一样,到了android 4.4之后,就只要高宽不超过原来的就行了。Bitmap是分配在dalvik heap上的,只有这样才能解释bitmap容易导致OOM。
3. Bitmap的有关讲解与优化
二、常见的问题
1. Attempt to invoke virtual method ‘int android.graphics.Bitmap.getWidth()’ on a null object reference
refer to 参考链接
问题描述
该问题通常是在调用getWidth() 方法时,对应的Bitmap有时候出现为null,导致getWidth()方法出现空指针。
可能的原因
- No read permission
- The image file is corrupt
- There is not enough memory to decode the file
- The resource does not exist
- Invalid options specified in the options variable.
建议的调试方法:
通过引入if(unscaledBitmap == null)
的判断,进行断点调试。
public class BitmapScalingHelper{ public static Bitmap decodeResource(Resources res, int resId, int dstWidth, int dstHeight) { Options options = new Options(); options.inJustDecodeBounds = true; BitmapFactory.decodeResource(res, resId, options); options.inJustDecodeBounds = false; options.inSampleSize = calculateSampleSize(options.outWidth, options.outHeight, dstWidth, dstHeight); options = new Options(); //May use null here as well. The funciton may interpret the pre-used options variable in ways hard to tell. Bitmap unscaledBitmap = BitmapFactory.decodeResource(res, resId, options); if(unscaledBitmap == null) { Log.e("ERR","Failed to decode resource - " + resId + " " + res.toString()); return null; } return unscaledBitmap; }}
可以尝试的解决办法:
- 通过BitmapFactory.decodeByteArray把byte[]转成Bitmap出现的OOM的解决方法
- 替换成
SoftReference softRef = new SoftReference(BitmapFactory.decodeStream( input, null, options));
- 替换成
- Android - BitmapFactory.decodeByteArray - OutOfMemoryError (OOM):
- 引入System.gc();
2. Free memory of a byte array in Java
byte[] myArray = new byte[54];myArray = null;yourArray = myArray;yourArray = null;
三、测试相关
3.1 测试命令
while true; do dumpsys meminfo 23637 | grep "TOTAL SWAP PSS:"; sleep 2; done,
while true; do dumpsys -t 600 meminfo --unreachable 7898 | grep "unreachable allocations" ; sleep 1; done
3.2 测试命令的差异
前者监控的是实际占用的内存,后者unreachable allocations监控的是(需要java的垃圾管理器要去释放的内存)
3.3 测试相关资料
Android系统查看某个进程的线程
linux下top命令参数解释
垃圾回收机制与调用System.gc()区别
四、测试结论
JNIEXPORT jint JNICALL Java_org_apache_tvm_LibInfo_tvmArrayCopyFromJArray( JNIEnv *env, jobject obj, jbyteArray jarr, jlong jfrom, jlong jto) { jbyte *data = env->GetByteArrayElements(jarr, NULL); DLTensor *from = reinterpret_cast<DLTensor*>(jfrom); //from->data = static_cast(data); memcpy(from->data, static_cast<void *>(data), 150528); int ret = TVMArrayCopyFromTo(static_cast<TVMArrayHandle>(from), reinterpret_cast<TVMArrayHandle>(jto), NULL); free(from->data); from->data = NULL; env->ReleaseByteArrayElements(jarr, data, 0); ret
五、其他资料
pthread_create failed: couldn’t allocate 1069056-bytes mapped space: Out of memory
Android 启动线程OOM
Android Framework中的线程Thread及它的threadLoop方法
JNI的原理及内存详解
更多相关文章
- Android(安卓)匿名共享内存C接口分析
- android内存分析工具- MAT的初识(1)
- geekband android #5 第九周分享
- 【进阶】从linux到android,进程的方方面面
- android的一些常识
- Android:使用命令行工具adb、mksdcard等
- Android避免context相关内存溢出
- Android自学笔记:应用程序基本原理
- Android跨进程通信-AIDL