Android内存泄露

一、app内存泄露调试

1、通过adb shell dumpsys meminfo  packageName来查看内存使用状况
在没有打开应用的情况下,该命令返回的数据是这样的:

Android内存泄露

2、打开这个应用的MainActivity,再通过命令查看:

Android内存泄露

可以看到打印出来很多的信息,而对于我们查看Activity内存泄漏来说,只需要关注Activities和Views两个信息即可,在应用中存在的Activity对象有一个,存在的View对象有13个。

3、这时候我们退出这个Activity,在用命令查看一下:

Android内存泄露

可以看到,Activity对象和View对象都在极短的时间内被回收掉了。再次打开,退出,多次尝试,发现情况都是一样的。我们可以通过这种方式来简单判断一个Activity是否存在内存泄漏,最后是否能够被回收。
4、再运行刚才的泄漏的例子,用命令查看一下:

Android内存泄露

当我们连续打开退出同一个页面,然后使用命令查看时,发现Activity存在13个,而View则存在了234个,而且没有很快被回收,依次判断应该是存在内存泄漏了。

等待10多秒,再次查看,发现Activity和View的数量都变成了0。

Android内存泄露

上面的例子,是Handler临时性内存泄漏,只要Handler post的代码块执行完毕,被引用的Activity就能够释放。
除了临时性内存泄漏,还有危害更大,直到程序结束才能被释放的内存泄漏。

5、

Android内存泄露

android程序内存被分为2部分:native和dalvik,对于内存的限制是 native+dalvik 不能超过最大限制。

android程序内存一般限制在16M,也有24M的。
Native Heap Size 约等于Native Heap Alloc + Native Heap Free

Native Heap:Native代码分配的内存,虚拟机和Android框架分配内存。

Dalvik Heap:Java对象分配的占据内存

Dalvik Other:类数据结构和索引占据内存

Stack:栈内存

Ashmem:不以dalvik- 开头的内存区域,匿名共享内存用来提供共享内存通过分配一个多个进程可以共享的带名称的内存块。匿名共享内存(Anonymous Shared Memory-Ashmem。Android匿名共享内存是基于Linux共享内存的,都是在tmpfs文件系统上新建文件,并将其映射到不同的进程空间,从而达到共享内存的目的,只是,Android在Linux的基础上进行了改造,并借助Binder+fd文件描述符实现了共享内存的传递。

Other dev:内部driver占用的内存

.so mmap  C库代码占用的内存

.jar mmap  java文件代码占用的内存

.apk mmap apk代码占用的内存

.ttf mmap  ttf文件代码占用的内存

.dex mmap  dex文件代码占用内存。类函数的代码和常量占用的内存,dex mmap是映射classex.dex文件,Dalvik虚拟机从dex文件加载类信息和字符串常量等。Dex文件有索引区和Data区

Other mmap  其它文件占用的内存

6、app开发减少内存方法:

尽量不要在循环中创建太多的临时变量

尽量把大型的循环拆散,分段或按需执行

引入SDK库和调用新的系统API时,主要不常用功能的消耗,可考虑多进程方案,影响内存放入临时进程执行

调整Dex文件的顺序可以优化空间

二、其他命令

1、adb shell procrank

手机中的sh是经过精简过的。有些手机可能没有 procrank 命令。能够使用genymotion模拟器。或是自己安装procrank命令。使用procrank时,命令行的输出入下图:

Android内存泄露

能够看到,在linux下表示内存的耗用情况有四种不同的表现形式:
 VSS - Virtual Set Size 虚拟耗用内存(包括共享库占用的内存)
 RSS - Resident Set Size 实际使用物理内存(包括共享库占用的内存)
 PSS - Proportional Set Size 实际使用的物理内存(比例分配共享库占用的内存)
 USS - Unique Set Size 进程独自占用的物理内存(不包括共享库占用的内存)


VSS:VSS表示一个进程可訪问的所有内存地址空间的大小。

这个大小包含了进程已经申请但尚未使用的内存空间。在实际中非常少用这样的方式来表示进程占用内存的情况,用它来表示单个进程的内存使用情况是不准确的。
RSS:表示一个进程在RAM中实际使用的空间地址大小。包含了所有共享库占用的内存。这样的表示进程占用内存的情况也是不准确的。
PSS:表示一个进程在RAM中实际使用的空间地址大小,它按比例包括了共享库占用的内存。假如有3个进程使用同一个共享库,那么每一个进程的PSS就包括了1/3大小的共享库内存。

这样的方式表示进程的内存使用情况较准确。但当仅仅有一个进程使用共享库时,其情况和RSS一模一样。


USS:表示一个进程本身占用的内存空间大小,不包括其他不论什么成分,这是表示进程内存大小的最好方式!

能够看到:VSS>=RSS>=PSS>=USS

2、adb shell后 echo 3>/proc/sys/vm/drop_caches (清除一下系统cache)

3、adb logcat -v time  加上时间戳

4、采集某个应用的内存数据

这个实践和上面的脚本类似,只是命令不一样我另外单独列出来,因为这个有时候很有用。
比如,我们要采集com.tianxia.test的内存使用情况,分析它是不是会内存泄露,脚步类似:

# !/system/bin/sh
#这个脚步比较粗糙,是这么个意思
file=/sdcard/cpu/mem_info.log
rm $file
until [ 1 -gt 10000 ]
do
echo -e "\n\n\n\n\n---------------">>$file
date >> $file
dumpsys meminfo com.tianxia.test >> $file
sleep 3
done

 

上一篇:c – 如何一次写入超过2G的数据()


下一篇:(原创)JAVA多线程二线程池