Android内存泄露

Stella981
• 阅读 733

一、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

 5、查看单个应用程序最大内存限制

adb shell getprop|grep heapgrowthlimit

设备不一样 最大内存限制也可能不一样

点赞
收藏
评论区
推荐文章
blmius blmius
2年前
MySQL:[Err] 1292 - Incorrect datetime value: ‘0000-00-00 00:00:00‘ for column ‘CREATE_TIME‘ at row 1
文章目录问题用navicat导入数据时,报错:原因这是因为当前的MySQL不支持datetime为0的情况。解决修改sql\mode:sql\mode:SQLMode定义了MySQL应支持的SQL语法、数据校验等,这样可以更容易地在不同的环境中使用MySQL。全局s
Easter79 Easter79
2年前
swap空间的增减方法
(1)增大swap空间去激活swap交换区:swapoff v /dev/vg00/lvswap扩展交换lv:lvextend L 10G /dev/vg00/lvswap重新生成swap交换区:mkswap /dev/vg00/lvswap激活新生成的交换区:swapon v /dev/vg00/lvswap
Jacquelyn38 Jacquelyn38
2年前
2020年前端实用代码段,为你的工作保驾护航
有空的时候,自己总结了几个代码段,在开发中也经常使用,谢谢。1、使用解构获取json数据let jsonData  id: 1,status: "OK",data: 'a', 'b';let  id, status, data: number   jsonData;console.log(id, status, number )
皕杰报表之UUID
​在我们用皕杰报表工具设计填报报表时,如何在新增行里自动增加id呢?能新增整数排序id吗?目前可以在新增行里自动增加id,但只能用uuid函数增加UUID编码,不能新增整数排序id。uuid函数说明:获取一个UUID,可以在填报表中用来创建数据ID语法:uuid()或uuid(sep)参数说明:sep布尔值,生成的uuid中是否包含分隔符'',缺省为
Wesley13 Wesley13
2年前
Java获得今日零时零分零秒的时间(Date型)
publicDatezeroTime()throwsParseException{    DatetimenewDate();    SimpleDateFormatsimpnewSimpleDateFormat("yyyyMMdd00:00:00");    SimpleDateFormatsimp2newS
Stella981 Stella981
2年前
Android So动态加载 优雅实现与原理分析
背景:漫品Android客户端集成适配转换功能(基于目标识别(So库35M)和人脸识别库(5M)),导致apk体积50M左右,为优化客户端体验,决定实现So文件动态加载.!(https://oscimg.oschina.net/oscnet/00d1ff90e4b34869664fef59e3ec3fdd20b.png)点击上方“蓝字”关注我
Wesley13 Wesley13
2年前
mysql设置时区
mysql设置时区mysql\_query("SETtime\_zone'8:00'")ordie('时区设置失败,请联系管理员!');中国在东8区所以加8方法二:selectcount(user\_id)asdevice,CONVERT\_TZ(FROM\_UNIXTIME(reg\_time),'08:00','0
Wesley13 Wesley13
2年前
00:Java简单了解
浅谈Java之概述Java是SUN(StanfordUniversityNetwork),斯坦福大学网络公司)1995年推出的一门高级编程语言。Java是一种面向Internet的编程语言。随着Java技术在web方面的不断成熟,已经成为Web应用程序的首选开发语言。Java是简单易学,完全面向对象,安全可靠,与平台无关的编程语言。
Wesley13 Wesley13
2年前
MySQL部分从库上面因为大量的临时表tmp_table造成慢查询
背景描述Time:20190124T00:08:14.70572408:00User@Host:@Id:Schema:sentrymetaLast_errno:0Killed:0Query_time:0.315758Lock_
Python进阶者 Python进阶者
4个月前
Excel中这日期老是出来00:00:00,怎么用Pandas把这个去除
大家好,我是皮皮。一、前言前几天在Python白银交流群【上海新年人】问了一个Pandas数据筛选的问题。问题如下:这日期老是出来00:00:00,怎么把这个去除。二、实现过程后来【论草莓如何成为冻干莓】给了一个思路和代码如下:pd.toexcel之前把这