本文转载自: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 内存泄漏问题【转】相关推荐

  1. android释放acitity内存,Android 内存泄漏分析与解决方法

    在分析Android内存泄漏之前,先了解一下JAVA的一些知识 1. JAVA中的对象的创建 使用new指令生成对象时,堆内存将会为此开辟一份空间存放该对象 垃圾回收器回收非存活的对象,并释放对应的内 ...

  2. Android内存泄漏就这样产生了

    为什么80%的码农都做不了架构师?>>>    1.资源对象没关闭造成的内存泄漏 描述: 资源性对象比如(Cursor,File文件等)往往都用了一些缓冲,我们在不使用的时候,应该及 ...

  3. Android内存泄漏总结

    Android 内存泄漏总结 箫鉴哥 2016-01-19 13:44:26 浏览42979 评论10 android 性能优化 阿里技术协会 内存管理 内存泄漏 摘要: Android 内存泄漏总结 ...

  4. Android 内存泄漏总结文档

    2019独角兽企业重金招聘Python工程师标准>>> Android 内存泄漏总结 内存管理的目的就是让我们在开发中怎么有效的避免我们的应用出现内存泄漏的问题.内存泄漏大家都不陌生 ...

  5. Android内存泄漏分析及调试

    2019独角兽企业重金招聘Python工程师标准>>> Android内存泄漏分析及调试 分类: Android2013-10-25 11:31 5290人阅读 评论(5) 收藏 举 ...

  6. Android 内存泄漏分析指北

    android 内存泄漏分析指北 简单来说内存泄漏就是当对象不再被应用程序使用,但是垃圾回收器却不能移除它们,因为它们正在被引用 java 垃圾回收介绍: Java 虚拟机运行所管理的内存包括以下几个 ...

  7. Android内存泄漏的检测流程、捕捉以及分析

    https://blog.csdn.net/qq_20280683/article/details/77964208 Android内存泄漏的检测流程.捕捉以及分析 简述: 一个APP的性能,重度关乎 ...

  8. Android内存泄漏的各种原因详解

    转自:http://mobile.51cto.com/abased-406286.htm 1.资源对象没关闭造成的内存泄漏 描述: 资源性对象比如(Cursor,File文件等)往往都用了一些缓冲,我 ...

  9. Android 内存泄漏分析与解决方法

    Android 内存泄漏分析与解决方法 参考文章: (1)Android 内存泄漏分析与解决方法 (2)https://www.cnblogs.com/start1225/p/6903419.html ...

  10. android 内存泄漏分析工具,Android内存泄漏终极解决篇(上)

    一.概述 在Android的开发中,经常听到"内存泄漏"这个词."内存泄漏"就是一个对象已经不需要再使用了,但是因为其它的对象持有该对象的引用,导致它的内存不能 ...

最新文章

  1. mongo go 查询指定字段_Go语言 操作MongoDB数据库批量查询
  2. php常用案例,PHP常用数组处理函数总结,附带运行案例
  3. 前端性能优化最佳实践(转)
  4. 强化学习与深度,神经网络的结合随记
  5. SQLite 数据库注入总结
  6. Mac计算器的计算过程怎么看?教你一键查看运算记录!
  7. python module: csv
  8. php生成gif动态图片_PHP绘制GIF动态图片
  9. FPGA实现对数log2和10*log10
  10. 电脑变慢,电脑越来越慢怎么办 电脑用久了网速变慢如何解决
  11. JS——数组中去除空空字符串
  12. 教你学Python38-利用SVD简化数据
  13. 如何下载bing必应首页图片
  14. 你听说过FOC吗?FOC的原理是什么?
  15. Ztree之初涉——简单Ztree的实现
  16. redis状态与性能监控
  17. 微信清理网页缓存的办法
  18. 安卓讲课笔记3.4 网格布局
  19. 人脸识别主要算法原理和公司
  20. 前端小字典 (2)– Base64

热门文章

  1. Python对我下手了!学会这几个知识点可以救命!
  2. 细节也可以决定网站中交互设计的成败
  3. pandas 调整列的顺序
  4. C++使函数返回多个数组
  5. python入门必备10个坑_python中的基础坑
  6. 蓝桥杯2020年第十一届C++省赛第六题-成绩统计
  7. 蓝桥杯2017年第八届C/C++省赛C组第一题-贪吃蛇长度
  8. Android IPC(二)Messenger实现跨进程双向通信
  9. Eclipse 使用和问题总结
  10. Java ==和equals有什么区别?