java内存泄露定位有哪些方法定位,崩溃有哪些方法

2011年 总版技术专家分年内排行榜第三2010年 总版技术专家分年内排行榜第三
2012年 总版技术专家分年内排行榜第五
2008年2月 VB大版内专家分月排行榜第一2003年4月 VC/MFC大版内专家分月排行榜第一2002年11月 VC/MFC大版内专家分月排行榜第一
2011年11月 VC/MFC大版内专家分月排行榜第二2008年3月 VB大版内专家分月排行榜第二2008年3月 硬件/嵌入开发大版内专家分月排行榜第二2003年4月 其他开发语言大版内专家分月排行榜第二2003年4月 VB大版内专家分月排行榜第二2003年3月 VB大版内专家分月排行榜第二
2008年2月 VB大版内专家分月排行榜第一2003年4月 VC/MFC大版内专家分月排行榜第一2002年11月 VC/MFC大版内专家分月排行榜第一
2011年11月 VC/MFC大版内专家分月排行榜第二2008年3月 VB大版内专家分月排行榜第二2008年3月 硬件/嵌入开发大版内专家分月排行榜第二2003年4月 其他开发语言大版内专家分月排行榜第二2003年4月 VB大版内专家分月排行榜第二2003年3月 VB大版内专家分月排行榜第二
匿名用户不能发表回复!|一次linux内存泄露问题定位过程 - 为程序员服务
一次linux内存泄露问题定位过程
1 问题现象
在一音频处理服务程序的稳定性测试过程中,音频处理服务程序所在服务器的Memory%使用率持续上涨,如图1所示。第一反应就是服务程序内存有泄露。
图1 音频处理服务器所在服务器的内存使用占用率
对于C++应用的内存问题,首先想到的是上内存问题定位神器Valgrind,《Valgrind介绍和使用》
2 分析过程
2.1 第一次分析-Valgrind
使用Valgrind对音频处理应用tobie进行分析结果如下,果然有泄露的对象。根据堆栈和代码行提示,可以看出http.c的第2695行evhttp_encode_uri方法调用malloc的内存没有回收。
==24853== 2,272 bytes in 568 blocks are definitely lost in loss record 92 of 107
at 0x4C28D84: malloc (vg_replace_malloc.c:291)
by 0x5135A9: evhttp_uriencode (http.c:2695)
by 0x4AE2D5: tobie2_worker(void*) (http_server.cpp:512)
by 0x713BB4F: start_thread (pthread_create.c:304)
by 0x7DF920C: clone (clone.S:112)
根据堆栈提示,找到有泄露的代码行。原Bug处evhttp_encode_uri处理后对象没有进行free
findAndReplace(fulluri,TOBIE_CHAIN_TAG,evhttp_encode_uri(TOBIE_CHAIN_TAG));
修改如下,将malloc的内存free掉。
char *tobie_chain_tag = evhttp_encode_uri(TOBIE_CHAIN_TAG);
findAndReplace(fulluri,TOBIE_CHAIN_TAG,tobie_chain_tag);
free(tobie_chain_tag);
修复后用Valgrind验证已无definitely lost的对象,还存在一些still reachable和possiblely lost的对象,从中选择一些对象进行分析,基本是程序运行前加载的一些全局对象,问题不大。然后再继续进行稳定性测试,一段时间后运维平台查看的Memory%使用仍然上涨,如图2所示:
图2 音频处理服务器所在服务器的内存使用占用率
为什么会这样?难道神器不灵了?
2.2 第二次分析-GDB
再把Valgrind的分析结果梳理一遍,发现了一个约96M的大对象,如图3所示。根据堆栈信息初步判断它是用于统计请求信息的对象,会不会随着请求越来越多,它的大小就累计了呢,从而导致应用的内存使用持续增加。
图3 Valgrind分析结果截图
那么问题来了,如何实时地去查看对象或变量的变化呢?这时候GDB就可以派上用场了,GDB不仅是在开发调试时用处很大,有时候在定位问题上也起到显著作用。对怀疑的对象RotateStatisticsBuffer进行分析,让测试程序和服务程序持续运行一段时间后,查看RotateStatisticsBuffer对象中的firstBuffer和SecndBuffer值:
#gdb attach PID
Continuing.
(gdb) p httpServer.rotateStatisticsBuffer.firstBuffer.size()
(gdb) p httpServer.rotateStatisticsBuffer.secondBuffer.size()
$17 = 2808
Continuing.
(gdb) p httpServer.rotateStatisticsBuffer.secondBuffer.size()
(gdb) p httpServer.rotateStatisticsBuffer.firstBuffer.size()
$19 = 1341
通过GDB调试结果可以看到统计信息RotateStatisticsBuffer对象中的FirstBuffer和SecndBuffer值并不会持续增长,SecndBuffer值达到设定值后会清空为0 ,将数据复制到FirstBuffer。从结果来看Valgrind的分析还是值得信赖的。
2.3 第三次分析-TOP
切换分析思路,我们应该明确运维平台Memory%究竟是如何计算的,或许问题并不是在服务应用上,而是对运维平台的Memory%理解有问题。直接用Top命令查看,发现当前音频处理服务应用的所有进程的内存总和远小于运维平台的Used Memory。音频处理服务Tobie是一个多进程的应用,子进程主要用于每个音频的处理,当其处理数目达到上限就会kill掉,所以子进程不会导致内存的持续上涨,主要是还是看tobie主进程内存的变化。如4所示测试前音频处理应用Tobie的内存大小9.8M,其中PID=484为Tobie主进程。
测试前Top命令结果:
图4 测试前Top命令结果
测试结束后Tobie主进程的内存大小约10M,和测试前大小基本无变化。
图5 测试后Top命令结果
通过Valgrind分析结果和Top统计的进程由此我们可以基本判定,被测应用Tobie处理服务是没有内存泄露的。那么这么多的内存究竟被谁用了呢?
2.4 第四次分析-Free
我们知道运维平台和free命令都是对/proc/meminfo的值进行的统计和计算。使用free 命令查看测试一段时间前后的内存变化。 测试开始前机器内存情况:
nos@10-120-202-235:~/nos_perftest/tobie-2.0.2/tmp$ free -m
-/+ buffers/cache:
测试停止机器内存情况:
-/+ buffers/cache:
从数据上可以看出来cached的内存增长了很多,近8个G,而除去cached和buffer的 uesd memory 增长2个G。cached memory增加可以解释,原因是tobie在音频转码后的文件会保存为临时文件,当处理结果返回给用户后才会将生成的临时文件删除,由于tobie生成的临时文件的名字是不重复的,所以大量文件被缓存到文件系统的cache中,cached mem增加是可以解释的。但是used memory为什么会增加2G,而进程的内存根本没有那么大,那used memory除了进程内存大小还包括什么呢?
将系统的Cache手工进行清除,从运维平台观察到看到Memory%下降到最初的值,如图6所示:
图6 音频处理服务所在机器Mem%使用
为什么释放系统的cahced mem ,机器的实际使用的used mem也会下降?而已知的used mem=used – buffers -cached,难道不是这么计算的?重重疑问解释不了。这时候开始对运维平台和free 命令的统计方式都产生了怀疑,因此直接去看它们计算的数据来源/proc/meminfo,其中有一项Slab mem的值正好在2G左右,难道free 和运维平台把这块值都计算到used mem里面的?Google一下slab,简单的说内核为了高性能每个需要重复使用的对象都会有个池,这个slab池会cache大量常用的小对象,比如说dentry和inode,所以会消耗大量的内存。使用Slabtop命令查看其中Denty对象大小占用果然约2个G,那么证明了推测,Dentry和Inode的缓存并没有计入到cached mem中去,而是计算在used mem里面的,这跟之前的理解是不一致的,我们大多认为所有的文件相关的缓存都是计算在cached mem里面的。
为了进一步说明问题,再进行了反向的验证和推测。通过修改drop_caches的值来手工清理系统的缓存。
应用程序运行一段时间后,used mem约7G,cached mem约31G左右,如图7所示:
图 7 系统cache未清理前free命令结果
将/proc/sys/vm/drop_caches 为1,释放page cache后,cache mem释放了很多,只剩下27M,而used mem剩余6G多,如图8所示:
图8 释放page cache后free命令结果
将/proc/sys/vm/drop_caches 为2,释放dentries and inodes后,-buffer-cache的值,也就是used mem的值,从7G下降到了680M,如图9所示:
图9 释放dentries and inodes后free命令结果
由此可以得出used mem确实是将slab cache的大小,也就是dentry和inode的缓存大小计算在内的
1) linux系统内存消耗主要有三个地方:1 进程 ,2 slab,3 pagecacge,我们用free 命令查看到的是系统整体的内容使用情况,而使用ps和top看到的内存使用情况都是以进程维度来看的,因此看不到slabcache和pagecache的内存占用信息。
2) 判断应用程序是否有内存泄露问题,只根据进程的内存使用或机器的内存变化来判定都不太准确,如果单凭进程的内存变化可能会疏忽一些小对象的内存泄露问题。同时对于机器的内存的使用也要做是否合理的判断。对于不同语言的应用都有相应的神器可以辅助定位内存泄露问题,同时结合linux内存的监控工具进行分析,除了本文提到的top,free还有pmap,/proc/meminfo和/slabinfo,slaptop等。
3) 通过这个问题,有一点比较重要的是,在使用监控工具进行监控和分析时,对其值的具体含义还是要了解的很清楚,否则会造成误判,使问题变得更加复杂。
4) 此外,对于文中提到的page cache,dentries和inodes cache,系统是会自动回收的。我们可以通过以下几种方式加速其回收,不过实际并不需要这么做。
- 手工清除缓存**
echo 1 & /proc/sys/vm/drop_caches
清除page cache
echo 2 & /proc/sys/vm/drop_caches
清除denries和inodes
echo 3 & /proc/sys/vm/drop_cache
清除page cache ,dentries及inodes
- 调整vm.vfs_cache_pressure值大小,默认是100.值越大,dentries和inodes cache的回收速度会越快
- 调整vm.min_free_kbytes值大小,该值为系统开始内存回收的阀值。越大表示系统会越早开始回收。不过根据查阅资料此值不建议调整。
4 知识笔记
4.1 关于Free命令
表1 Free命令结果的含义
总物理内存
使用内存(slab+buffer+cached)
完全没被使用的内存
进程间共享内存
文件元数据缓存
文件内容缓存
-/+ buffer/cache
当前使用内存(不包括buffer和cache,但包括slab)
未使用和缓存的内存(free+buffers+cached)
总共交换空间
已使用的交换空间
未使用的交换空间
4.2 关于TOP命令
TOP命令内存监控的内容包括了机器内存的整体情况,也包括了进程的内存使用情况。其中机器内存的使用情况和free命令一致,不赘述
图10 TOP命令结果
表2 TOP命令结果中内存相关的变量值含义
进程使用的虚拟内存总量,VIRT=SWAP+RES
进程使用的虚拟内存中,被换出的大小
进程常驻内存,未被换出的物理内存,RES=CODE+DATA
可执行代码占用的物理内存大小
进程使用的数据段+栈占用的内存大小
共享内存大小
靡不有初 鲜克有终
原文地址:, 感谢原作者分享。
您可能感兴趣的代码内存泄露有哪些方法定位,崩溃有哪些方法定位_百度知道
内存泄露有哪些方法定位,崩溃有哪些方法定位
我有更好的答案
下面是自己遇到的一些比较隐秘的造成内存泄漏的情况:1.两个对象互相拥有,如果内存增长为0就证明我们程序在该次循环操作中不存在内存泄漏,如果内存增长不为0那证明有可能存在内存泄漏,当然具体问题需要具体分析,b对象add到了c对象上,而在我们的设计中b对象的生命周期应该和a对象相同;通过静态分析我们可以最初步的了解到代码的一些不规范的地方或者是存在的内存泄漏,这是我们第一步对内存泄漏的检测。当然有一些警告并不是我们关心的可以略过。2.通过instruments来检查内存泄漏这个方法能粗略的定位我们在哪里发生了内存泄漏。准确的说就是init(创建对象的方法)和dealloc是否会被成对触发(简单说来就是走一次创建对象就有走一次dealloc该对象)ios怎么查看内存泄露,要用assign属性也会导致互相拥有。2.有时候需要用removeFromSuperView来释放,在dealloc的方法中我们是否已经释放了该对象所拥有的所有对象。观察对象的生成和销毁是否配对:delegate不要用retain属性。3,而b并不是a的subView,所有最后的一次-1没有了);所以我们需要在之前加上[b removeFromSuperView].代码测试内存泄漏在做这项工作之前我们要注意一下;这时候只一句[b release]/self.b = nil是不能把b对象释放掉的(一般情况下release会使其retainCount-1,[super dealloc]会再次将所有subView的retainCount-1:也就是说对象a里面retain/addSubview了b对象,b对象同时也retain/addSubView了a对象。注意:具体说明,也许我的a对象拥有一个b对象,有以下几种方法供大家参考:静态分析&nbsp。方法是完成一个循环操作
采纳率:95%
为您推荐:
其他类似问题
换一换
回答问题,赢新手礼包
个人、企业类
违法有害信息,请在下方选择后提交
色情、暴力
我们会通过消息、邮箱等方式尽快将举报结果通知您。排查内存泄漏最简单和直观的方法 - 简书
排查内存泄漏最简单和直观的方法
内存泄漏无疑会严重影响用户体验,一些本应该废弃的资源和对象无法被释放,导致手机内存的浪费,app使用的卡顿,那么如何排查内存泄漏呢?当然,首先我门有google的官方文档可以参考:
大部分博客的方法也来自于此。总的来说,就是使用android studio 的monitor memory功能监测app主进程占用的内存,触发GC操作,而后观察内存的占用情况,如果在使用的过程中内存不断增加,没有回落,很有可能发生了内存泄漏,这时候就需要导出内存分配的具体详情进行深入分析了。
内存监测曲线
但是事实上,通过观察这个内存曲线的曾场来或者是观察allocate tracker中的allocate data数值的增长来检测是否有内存泄漏问题,真的很玄,因为往往内存泄漏发生了,但是GC仍然可以通过回收其他对象的方式腾出空间,导致这个数据的变化基本看不出来,甚至是减小的,所以我觉得这种方式,就像是让你用手掌去感知婴儿的体温,去检测确定这个婴儿有没有发烧一样,非常不靠谱不准确。那么,重点来了,我的方法,简单直观,保准你一学就会!第1步:检测内存泄漏先说一个terminal指令: adb shelldumpsys meminfo (pid name)这条指令是用来查询这个进程所占用的内存的具体详情的,通过这条指令可以看到当前app在手机中占用的具体的堆内存大小,view的数量,activity的数量,等等。如下图:
进程内存分配详情
其中activity数目是非常关键的一个信息,可以帮助我们快速地检测出内存泄漏。我们可以反复地进入退出需要测试的目标activity,如果在反复进入退出之后,用terminal执行上面的语句查询当前的内存情况,如果发现activity数量一直在增长,那么内存泄露一定是发生了!第2步:定位内存泄漏的原因
内存泄漏已经发生,如何定位原因呢?方法1:
如下图,在android studio中开始memory monitor,点击init GC,反复进入退出发生了内存泄漏的activity,这时候点击生成内存文件,这之后android studio会自动打开生成的.hprof文件。选中该文件转化成标准的hrof文件。
用MAT工具打开生成的.hprof文件,点击如下所示的图标,可以看到内存中的对象列表。
考虑到大内存的泄漏都是因为Activity被destroy之后却仍然被其他对象持有而造成的,因此首先解决棘手问题,直接搜索Activity,如下。发现有Activity的实例个数是3,跟实际不符,明显这个activity导致内存泄漏了,按照如图的方式找到它的引用,也就是导致内存泄漏的幕后凶手!
可以看到这个例子中的内存泄漏是由一个HandlerThread引发的,那么找到这个问题的位置,在合适的地方(如ondestroy)将这个handler thread释放即可。方法2: Android Studio自带的Analyzer Tasks
如下图所示: 在android studio中打开生成的hprof文件,在右侧边栏会出现的Analyzer Tasks工具,点击执行图标,即可出现检测分析的结果,得到哪些activity被泄漏了,这些被泄漏的activity被谁引用了。可以看到内存泄漏由AsyncHandler引起,需要在activity生命周期结束的时候进行释放。
android studio自带的分析工具
方法2不用安装MAT工具,更加便捷哦~希望这篇文章可以帮助你快速发现和定位内存泄漏。
有问题可以留言,谢谢您的阅读~~
萌萌哒程序媛
用两张图告诉你,为什么你的 App 会卡顿? - Android - 掘金 Cover 有什么料? 从这篇文章中你能获得这些料: 知道setContentView()之后发生了什么? ... Android 获取 View 宽高的常用正确方式,避免为零 - 掘金 相信有很多...
用两张图告诉你,为什么你的 App 会卡顿? - Android - 掘金Cover 有什么料? 从这篇文章中你能获得这些料: 知道setContentView()之后发生了什么? ... Android 获取 View 宽高的常用正确方式,避免为零 - 掘金相信有很多朋友...
被文同时发布在CSDN上,欢迎查看。 APP内存的使用,是评价一款应用性能高低的一个重要指标。虽然现在智能手机的内存越来越大,但是一个好的应用应该将效率发挥到极致,精益求精。 本文是【Android 性能优化】系列的第二篇文章,我们在第一篇【Android 性能优化】—— ...
作者:小强 贝聊移动开发部 Android工程师 1.Java内存分配策略 Java 程序运行时的内存分配策略有三种:静态分配、栈式分配和堆式分配。对应的存储区域如下: 静态存储区(方法区):主要存放静态数据、全局 static 数据和常量。这块内存在程序编译时就已经分配好...
内存管理的目的就是让我们在开发中怎么有效的避免我们的应用出现内存泄漏的问题。内存泄漏大家都不陌生了,简单粗俗的讲,就是该被释放的对象没有释放,一直被某个或某些实例所持有却不再被使用导致 GC 不能回收。最近自己阅读了大量相关的文档资料,打算做个总结沉淀下来跟大家一起分享和学...
王卫江春天刚做了眼睛的白内障手术,因为术后感染所以在家休息。因为检修,车间的一声召唤,便马上投入到工作中!为了保护眼睛,天天戴墨镜上班。虽然戴着墨镜,却丝毫不会影响工作。因为检修末期,要为开工做准备,班长安排王师傅校准PH计。校准PH计简单的说就是用已知准确PH的标准溶液,...
曾经因为颜值太低,没有被北电录取,现在美得这么自然 从《小兵张嘎》里的英子,到《武林外传》里的莫小贝,从北电遭遇失败到如今美的自然,回望王莎莎的这一路星途,现在是越来越顺。 王莎莎的微博一年没有更新,在消失了一年之后,莎莎以一个新的形象走进大众视野,我们不禁惊呼,那个胖胖的...
如何选购称重式拌料机?这就需要掌握实用性方式技巧,下面就由苏州三众机械有限公司的葛经理来分享购买称重式拌料机的一些技巧: 1.看产品能力 消费者在选购称重式拌料机产品时,一般要考虑使用空间的实际情况。例如:空间的格局,开放程度,太阳照射的强度、通风、人员数量等问题。通常,一...
外面大雪纷飞,客栈里烫着一壶酒与几碟小菜,一个男人在自斟自饮。 门被一个红袍女子推开,风雪吹进来,小二忙把门栓上,接过女子递来的袍衣。女子径直走向男子,在他的对面坐下,把剑放在桌旁,问:“找我来,什么事?” 男子仰头一饮而尽:“借样物品。”女子道:“倚天剑?”男子没有继续喝...}

我要回帖

更多关于 如何定位内存泄露 的文章

更多推荐

版权声明:文章内容来源于网络,版权归原作者所有,如有侵权请点击这里与我们联系,我们将及时删除。

点击添加站长微信