android 内存泄漏问题【转】
本文转载自:http://www.voidcn.com/article/p-hbnuyfwz-ee.html
内存泄露问题在一些压力测试的场景很容易暴露,例如一些常用应用场景反复操作(eg:反复切换前后摄像头,反复进入退出相机应用、压力拍照等等)。
内存泄露一般表现为:
①内存分配释放,导致进程空间虚拟地址被分配完,或者物理地址被分配完。
②文件泄露,导致进程空间文件句柄数达到最大值。
③线程泄露,导致进程空间虚拟地址被分配完,进程内保留很多线程栈(stack)。
Android Native层中大部分的泄露问题都在HAL层,主要导致原因就是一些非对称操作。
1. 工具
这一层主要使用工具为Linux自带的工具以及一些文件节点的状态。
命令列表:
ps [-t] [pid] [ | busybox wc -l ] top [-t] ll /proc/pid/fd [ |busybox wc -l ] cat /proc/pid/maps [ |busybox wc -l ] cat /proc/meminfo [ | grep "MemFree" ] dumpsys meminfo [ pid ] [ package name ] procrank valgrind valgrind |
2. ps / top命令
ps /top 可以对linux系统中进程进行监测和控制。Ps 是显示瞬间进程的状态;Top是对进程运行时间监控。
Ps/top命令查找到目标的进程号pid,再根据pid去观测反复操作中Ps/top的两项打印项:
VSIZE(VSS) :占用的虚拟内存的大小。
RSS :占用内存的大小。
确认下这两项是否一直在无限制增大,这样子可以初步确认一下内存泄露问题的存在性。
ps -t pid 这个命令可以列出当前进程所有线程,包括native线程和java线程。
native线程可以查看到其线程名,如:
USER PID PPID VSIZE RSS WCHAN PC NAME media 1574 1465 50312 9992 c0089920 b6ea491c SCameraCaptureTh |
Java 线程只能看到java线程在native层的映射名
USER PID PPID VSIZE RSS WCHAN PC NAME u0_a22 6884 2562 984204 54004 c0089920 4010491c SThread-194 |
查线程是否泄露技巧:可以在相同的状态反复使用下面命令,如在每次应用打开关闭后使用,这个命令可以统计目标进程内所有的线程数,这个数一直在增加的话,说明进程内存在进程内有线程没有正常被释放。
ps -t pid | busybox wc -c |
3. proc进程状态节点
Linux proc虚拟文件系统中会记载系统所有进程的一些状态信息,在/prco下会有进程目录,目录名就是pid。pid文件夹下信息量非常庞大,现在只介绍两个与查内泄漏相关的:fd目录和maps节点。
root@kylin-wt097:/ # ps mediaserver USER PID PPID VSIZE RSS WCHAN PC NAME media 8403 1 240688 16940 ffffffff b6f225a0 S /system/bin/mediaserver root@kylin-wt097:/ # ll /proc/8403 dr-xr-xr-x media audio 2012-02-14 12:55 attr ....................................... dr-x------ media audio 2012-02-14 12:55 fd -r--r--r-- media audio 0 2012-02-14 12:55 maps ....................................... -r--r--r-- media audio 0 2012-02-14 12:55 wchan |
①进程fd目录
可以看出fd目下为文件句柄的链接,例如17为文件句柄号,/system/etc/camera.cfg为打开的文件目录。
root@kylin-wt097:/ # ll /proc/8403/fd lrwx------ media audio 2012-02-14 13:02 0 -> /dev/null lrwx------ media audio 2012-02-14 13:02 1 -> /dev/null l-wx------ media audio 2012-02-14 13:02 10 -> /dev/log/system lr-x------ media audio 2012-02-14 13:02 11 -> /dev/__properties__ lr-x------ media audio 2012-02-14 13:02 16 -> /system/etc/camera.cfg lr-x------ media audio 2012-02-14 13:0217 -> /system/etc/camera.cfg l-wx------ media audio 2012-02-14 13:02 18 -> /dev/cpuctl/apps/tasks lrwx------ media audio 2012-02-14 13:02 3 -> /dev/binder lrwx------ media audio 2012-02-14 13:02 8 -> /dev/cpuctl/tasks l-wx------ media audio 2012-02-14 13:02 9 -> /dev/log/events ....................................... |
查看系统每个线程的文件句柄最大值,一般系统都会默认一个进程最多有1024个文件句柄,当一个进程打开文件句柄的数量达到1024时,再次创建文件句柄会失败,strerror(errno)会报出“Too many open files”。
cat /proc/pid/limits | grep "Max open files" |
查文件句柄是否泄露技巧:可以在相同的状态反复使用下面命令,如在每次应用打开关闭后使用,这个命令可以统计目标进程内所有文件句柄,这个数一直在增加的话,说明进程内存在进程内有文件句柄没有正常被关闭。
cat /proc/fd | busybox wc -c |
②进程maps节点
Maps节点可以查询进程的虚内存空间的使用情况。
该文件有6列,分别为:
地址:库在进程里地址范围
权限:虚拟内存的权限,r=读,w=写,x=,s=共享,p=私有;
偏移量:库在进程里地址范围
设备:映像文件的主设备号和次设备号;
节点:映像文件的节点号;
路径: 映像文件的路径
root@kylin-wt097:/ # cat /proc/8403/maps a9035000-a9525000 rw-s 98bb3000 00:09 2159 anon_inode:dmabuf ................................................................ a95bf000-a96bc000 rw-p 00000000 00:00 0 [stack:11334] a99fc000-ab17b000 rw-s 96354000 00:0c 31508 /dev/video0 ab17b000-ac8fa000 rw-s 94bd5000 00:0c 31508 /dev/video0 af7f8000-b0f77000 rw-s 90558000 00:0c 31508 /dev/video0 b0f77000-b26f6000 rw-s 8edd9000 00:0c 31508 /dev/video0 ................................................................ b26f9000-b27f6000 rw-p 00000000 00:00 0 [stack:11307] b27f6000-b27f8000 rw-p 00000000 00:00 0 ................................................................ b4bb4000-b4bb5000 r--p 00001000 b3:07 1091 /system/lib/libril_audio.so b4bb5000-b4bb6000 rw-p 00002000 b3:07 1091 /system/lib/libril_audio.so .................................................................. b6f54000-b6f55000 r--p 0000f000 b3:07 149 /system/bin/linker b6f55000-b6f56000 rw-p 00010000 b3:07 149 /system/bin/linker b6f56000-b6f57000 rw-p 00000000 00:00 0 b6f57000-b6f59000 r-xp 00000000 b3:07 162 /system/bin/mediaserver b6f5a000-b6f5b000 r--p 00002000 b3:07 162 /system/bin/mediaserver b6f5b000-b6f5c000 rw-p 00000000 00:00 0 b852b000-b859d000 rw-p 00000000 00:00 0 [heap] bea7c000-bea9d000 rw-p 00000000 00:00 0 [stack] ffff0000-ffff1000 r-xp 00000000 00:00 0 [vectors] |
32位Liunx系统每个进程有4G地址空间,android系统下进程地址空间分部如下:
高位1G空间为内核地址空间,地位3G空间为用户地址空间,可以看出栈stack是有高位向低位增长,而堆heap是由地位向高位增长,还有一段加载动态库的段,可以根据上面的catmaps打印出来对比。
堆泄露的定位方法:
下面是调用mmap映射得到进程虚拟地址,这样的打印持续增多的话,说明进程中有mmap 和 munmap没有对称操作,导致进程虚拟地址的泄露。
ab17b000-ac8fa000 rw-s 94bd5000 00:0c 31508 /dev/video0 |
下面是一个线程栈的使用情况, [stack:11334],11334为线程号tid,这样的打印持续增多的话,说明进程中会持续创建线程,但是没有释放旧线程。
a95bf000-a96bc000 rw-p 00000000 00:00 0 [stack:11334] |
③meminfo节点
proc/meminfo节点记录了系统内存的一些使用情况,主要看MemFree这项。
root@kylin-p1:/ # cat /proc/meminfo cat /proc/meminfo MemTotal: 1673008 kB所有可用RAM大小(即物理内存减去一些预留位和内核的二进制代码大小) MemFree: 761320 kB LowFree与HighFree的总和,被系统留着未使用的内存 .......................................... Mapped: 87932 kB 设备和文件等映射的大小。 .......................................... |
4. Android 工具
这是Android上实现的一些命令,在Native这层也可以使用,但是统计的一些信息也和上面的一样。
①dumpsys meminfo [ pid ] [ package name]
可以查看到某个线程(包括应用应用和系统线程)内存使用情况,包括Native堆和java堆。一般用来查java应用的进程,对于系统Native进程,dump出来信息较少。
②procrank
Androidprocrank (/system/xbin/procrank) 工具,能够列出进程所占用的内存使用情况。顺序为从高到低。每个进程占用内存大小以 VSS, RSS , PSS, USS 的形式列出。为了简化描述,内存占用以页为单位表述,而不是字节。 通常每页为 4096 字节。(和ps功能差不多,数据有少许差异)。
③valgrind
android sdk默认集成了valgrind,一款优秀的内存问题检测工具,能够发现内存泄漏。
当前的方案默认没有编译该工具,可以通过以下命令临时编译:
$ cd external/valgrind $ mm -j16 |
然后回到android根目录编译生产system.img。对于系统启动运行的进程需要,如debug surfaceflinger,需要在init.rc注释surfaceflinger service,改为命令行启动,
$root@kylin-perf:/ # valgrind --leak-check=full --log-file=/data/valgrind.log /system/bin/surfaceflinger & |
进行界面的一些简单操作后将surfacelinger进程kill掉,valgrind即会将分析报告输出到/data/valgrind.log,里面信息很多,附上相关的范例log:
关注leak summary:
==1982== LEAK SUMMARY: ==1982== definitely lost: 58,004 bytes in 477 blocks ==1982== indirectly lost: 376 bytes in 8 blocks ==1982== possibly lost: 122,997 bytes in 484 blocks ==1982== still reachable: 922,973 bytes in 20,141 blocks ==1982== suppressed: 0 bytes in 0 blocks ==1982== Reachable blocks (those to which a pointer was found) are not shown. ==1982== To see them, rerun with: --leak-check=full --show-reachable=yes ==1982== ==1982== For counts of detected and suppressed errors, rerun with: -v ==1982== Use --track-origins=yes to see where uninitialised values come from ==1982== ERROR SUMMARY: 673822 errors from 827 contexts (suppressed: 0 from 0) |
android 内存泄漏问题【转】的更多相关文章
- 【转】android 内存泄漏相关收藏博客。
关于android内存泄漏的研究 博客建了几个月,都没有去写,一是因为当时换工作,然后又是新入职(你懂的,好好表现),比较忙:二是也因为自己没有写博客的习惯了.现在还算是比较稳定了,加上这个迭代基 ...
- 关于android内存泄漏的研究
博客建了几个月,都没有去写,一是因为当时换工作,然后又是新入职(你懂的,好好表现),比较忙:二是也因为自己没有写博客的习惯了.现在还算是比较稳定了,加上这个迭代基本也快结束了,有点时间来写写博客.好了 ...
- Android内存泄漏的各种原因详解
转自:http://mobile.51cto.com/abased-406286.htm 1.资源对象没关闭造成的内存泄漏 描述: 资源性对象比如(Cursor,File文件等)往往都用了一些缓冲,我 ...
- Android 内存泄漏优化汇总
android内存泄漏优化摘要 博客分类: android android内存溢出OutOfMemoryError . android移动应用程序的内存分配一般是8凯瑟琳约,不正确地假定处理内存处理非 ...
- Android内存泄漏检测利器:LeakCanary
Android内存泄漏检测利器:LeakCanary MAR 28TH, 2016 是什么? 一言以蔽之:LeakCanary是一个傻瓜化并且可视化的内存泄露分析工具 为什么需要LeakCanary? ...
- Android 内存泄漏分析与解决方法
在分析Android内存泄漏之前,先了解一下JAVA的一些知识 1. JAVA中的对象的创建 使用new指令生成对象时,堆内存将会为此开辟一份空间存放该对象 垃圾回收器回收非存活的对象,并释放对应的内 ...
- [Android]Android内存泄漏你所要知道的一切(翻译)
以下内容为原创,欢迎转载,转载请注明 来自天天博客:http://www.cnblogs.com/tiantianbyconan/p/7235616.html Android内存泄漏你所要知道的一切 ...
- LeakCanary 来检查 Android 内存泄漏
LeakCanary 来检查 Android 内存泄漏
- Android内存泄漏的检测流程、捕捉以及分析
https://blog.csdn.net/qq_20280683/article/details/77964208 Android内存泄漏的检测流程.捕捉以及分析 简述: 一个APP的性能,重度关乎 ...
- Android内存泄漏原因
这段时间调试APP的时候,发现程序在加载了过多的bitmap后会崩溃.查看了日志,原来是发生了内存溢出(OOM).第一次遇到这样的问题,那就慢慢排查吧. 内存优化可以参考胡凯大神的博客Android内 ...
随机推荐
- mysql下监测数据库语句creating sort index时间过长的问题
在一张单表5000W数据上进行数据查询时传入两个单列索引条件,进行组合索引查询时,如果最后有order by id排序,与去除该排序,性能差距接近两个数量级 结论:在使用列的默认排序时,不应该再ord ...
- 跳转前暂停几秒js如何实现
jquery如何实现跳转前暂停几秒 今天有个需求,类似答题的,需要显示结果后再跳转. 此处直接通过settimeout实现. 代码如下: url = 'www.baidu.com'; setTimeo ...
- 搭建SpringMVC+Hibernate4+Spring3+Ajax+Maven项目
首先新建一个Maven项目.百度一下会有非常多实例,这里就不介绍了,直接奔主题. 如题:这里使用的是Hibernate4和Spring3,使用的JPA和Spring注解,然后JDK版本号是1.7 以下 ...
- ngui 输入事件处理
NGUI不仅提供了图形接口,还提供了输入事件接口!事件接口是通过UICamera来实现的. Unity3d 为我们提供的原装的input尽管非常方便,但真正跨平台使用时(尤其是跨手机与Pc机时)仍然不 ...
- jQuery--基础(查询标签)
浅谈jQuery使用背景 jQuery是使用原生js写成的一个库,使用简单,提高开发效率.在用js冗杂的代码解决的问题中,大部分都可以用jQuery来快速解决. 例如: js中查询网页中ID为&quo ...
- servletResponse 控制浏览器缓存
//当访问一些资源文件时,我们希望,访问一次后,资源文件能够在缓存在浏览器中,当我们再次访问该资源时 //直接从缓存中去取,这样可以减少服务器的压力 package response; import ...
- ASP.NET数据库连接字符串的加密与解密
ASP.NET web.config中,数据库连接字符串的加密与解密. 虽然不怎么新鲜,但相信还是有许多人不知道,好,不说废话,直接给方法:开始--->运行,输入cmd,接着输入以下内容 加密: ...
- android 编译问题解决
1.android4.2.2 '/root/origin_android/mokesoures/out/target/common/obj/APPS/ApplicationsProvider_inte ...
- Docker入门系列1:简介
可以实现快速部署. 比如一台 16 核 32G 内存的虚拟机上,需要跑 500+ 个用户的应用(每个应用的功能可以认为是一个网站 + 一系列的 RESTful API),有两个事情很重要: 资源隔离: ...
- ubuntu 12.10 笔记
笔记 more ec_unitouch.log |grep Thread-4 筛选日志 打开命令行终端 ctrl + alt + t 查看版本号 : sudo lsb_release -a t ...