文章目录

博客好长时间没有更新了,由于前段时间疯狂赶项目,有些问题没有来得及时整理,后面慢慢总结一下。

前段时间在优化相机扫描二维码时,遇到了一个内存溢出问题,内存被用完了,日志中出现E/dalvikvm-heap: Out of memory on a 2366828-byte allocation错误提示,App也没有崩溃,只是相机不再输出拍摄到的内容。使用Zxing做过二维码扫描的同学都知道,被扫描到的内容会不停的被处理,并识别出二维码内容,如果有。而此时内存被用完了的现象是:相应的回调处理识别二维码内容的方法没有被调用。于是展开了排查。

首先打开了ADM(Android Device Monitor),如果是AS 3.0以下,可以直接打开Android Monitor,点击Dump Java Heap按钮保存即可。然后启动App,选中当前App的进程,点击上面工具栏中的Update Heap按钮,在右侧的HeapTab页中就可以看到当前App的内存使用情况。如下图所示:

App内存分析

Update Heap按钮即为上图中标记为1的位置。

从上图中可以看出,byte[]对象占用内存较多,而内存一直增长的时候也就是这里的内存在增长。如图中标记为3的位置。byte[]对象一般是Bitmap对象,这个要看内存中的Depth

当App被限制的内存快要被使用完时(一般手机都会对单个App的内存使用限制,当App内无法再分配足够内存时,就会出现OOM),如图中标记为2的位置,点击右边的Dump HPROF file按钮,即可将内存信息保存为hprof文件。

再在Android Studio中Open保存的hprof文件,如下图所示:

App内存使用情况

在左侧点击byte[]行,可以在右侧看到对应的内存中的对象,发现byte[1382400]对象比较多,每个占用内存空间1M多。看到这个对象就反应过来了,扫描处理的对象是一个byte数组,而且长度是1382400。于是想到是不是JNI中内存没有释放。

到C++代码中排查了一下,byte数组从java层传到C++层时,使用GetByteArrayElements获取操作的数组后,并没有调用ReleaseByteArrayElements释放。修改代码如下所示:

1
2
3
4
5
6
7
8
JNIEXPORT jbyteArray JNICALL Java_zxing_utils_ImageUtils_demo
(JNIEnv *env, jclass jcls, jbyteArray jba, jint jlength) {
jbyte* raw = env->GetByteArrayElements(jba, NULL);
// 操作raw代码省略...
// 增加释放内存代码
env->ReleaseByteArrayElements(jba, raw, 0);
}

再编译运行,没有出现OOM了,问题解决。

文章目录