如何定位和处理gdb 定位内存泄露露

相信通过写java程序讨生活的人对内存溢出并不陌生,如下文字的出现更是让人恼火:
java.lang.OutOfMemoryError: Java heap space
java.lang.OutOfMemoryError: PermGen space
尤其当应用服务器(Java容器)出现上述情况更是让人有一种天塌下来的感觉。
好的编码实践可能会大大降低内存溢出的产生。
本文并不是写如何规避内存溢出,但是我还是要介绍一下如何能够尽量规避内存溢出:
1. 编码规范认真执行。找几个资深程序猿(或者整个项目组讨论后)写一个Java编码规范,让项目组成员尽量遵守。一目了然的代码更容易定位问题,当然也更能让人写出好的代码。
2. 单元测试要覆盖所有分支与边界条件。不要拿某种情况不会出现做借口。有句老话说常在河边站哪有不湿鞋(学名墨菲定律)。
3. 代码审查要走。代码写完了,找资深程序猿扫扫代码没有坏处。
4. 有条件的项目组要充分利用测试人员的能动性。
5. 如果项目的期望较高,就把上面的尽量、可能等词汇改成一定要。
以上五条建议对非性命攸关型项目足够了。
下面说正题:
对于java.lang.OutOfMemoryError: PermGen space 这种情况更多的是靠程序猿的经验来解决:
PermGen space的全称是Permanent Generation space,是指内存的永久保存区域, 这块内存主要是被JVM存放Class和Meta信息的,Class在被Load时就会被放到PermGen space中, 它和存放类实例(Instance)的Heap区域不同,GC(Garbage Collection)不会在主程序运行期对 PermGen space进行清理,所以如果你的应用中有很多CLASS的话,就很可能出现PermGen space错误。
通过上面的描述就可以得出:如果要加载的class与jar文件大小超过-XX:MaxPermSize就有可能会产生java.lang.OutOfMemoryError: PermGen space 。
换句话说-XX:MaxPermSize的大小要超过class与jar的大小。通常-XX:MaxPermSize为-Xmx的1/8。
对于java.lang.OutOfMemoryError: Java heap space 可能定位的过程就需要折腾一翻了:
虽然各种java虚拟机的实现机制不一,但是heap space内存溢出产生的原因相同:那就是堆内存不够虚拟机分配了。
我对java虚拟机的实现不感兴趣,对各种虚拟机的内存分配机制与gc的交互关系也不了解。但是我大致认为内存分配机制与gc是有联系的,也就是说内存不够分配时gc肯定也释放不了堆内存。从这一点出发,我们就需要找为什么gc释放不了堆内存。通常来说释放不了是因为内存还在使用。对于java对象产生的堆内存占用,只要其不再被继续引用gc是能够顺利回收的(对于通过本地方法调用,即JNI调用产生内存泄露的情况暂不考虑)。
问题的关键就找到了,当产生heap space内存溢出时,堆内存中对象数量过多的就可能是问题的根源了。例外的情况是,程序确实需要那么多内存,这时就要考虑增大堆内存。
例外的情况在本文中就不再多说了,下面介绍jdk自带的两个可视化工具来定位问题。
jdk/jconsole.exe
jdk/jvisualvm.exe
jconsole.exe可以查看本地以及远程主机上的java虚拟机的当前状况,这对服务器健康检查情况非常有用。如下图:
jvisualvm.exe可以用来查看分析内存转储文件;也可以用其做java虚拟机当前状况查看,但是jvisualvm.exe的侵入性非常强,一旦使用会严重影响应用性能。如下图:
下面写些代码来演示一下内存溢出的产生,堆转储文件的生成,堆内存的分析。
首先创建数据持有对象类:
package com.zas.jvm.
* 数据对象
* @author zas
public class DataObject {
//数据对象ID
//数据对象内容
public DataObject(String id, String des) {
this.des =
public String getId() {
public void setId(String id) {
public String getDes() {
public void setDes(String des) {
this.des =
public String toString() {
return &DataObject [id=& + id + &, des=& + des + &]&;
* @param args
public static void main(String[] args) {
溢出演示代码
package com.zas.jvm.
import java.util.ArrayL
import java.util.L
public class OutMemeryTest {
List&DataObject& list = new ArrayList&DataObject&();
public void testOm(){
for (int i = 0; i & 100000; i++) {
DataObject data = new DataObject(&id&&+i, &des:&+i);
list.add(data);
* @param args
public static void main(String[] args) {
OutMemeryTest omt = new OutMemeryTest();
for (int i = 0; i & 2; i++) {
omt.testOm();
System.out.println(&DOne!&);
Thread.sleep();
} catch (InterruptedException e) {
e.printStackTrace();
运行参数设置如下:-Xms64m -Xmx64m -XX:PermSize=8m -XX:MaxPermSize=8m
-XX:-HeapDumpOnOutOfMemoryError
jvisualvm分析效果图:
从上图结合代码明显得出:com.zas.jvm.om.DataObject这个类的对象出了问题。
以上是一个演示问题产生及定位过程,生产环境的问题千奇百怪需要具体问题具体分析。
当堆内存巨大时可能要调整jdk\lib\visualvm\etc\visualvm.conf文件中的-xms -xmx大小来导入转储文件。
生产环境为linux的较多,可以借助jdk自带的jmap来转储堆内存文件来分析。
相关 [java 内存 溢出] 推荐:
- CSDN博客推荐文章
JVM运行时内存 = 共享内存区 + 线程内存区. 共享内存区 = 持久带 + 堆. 持久带 = 方法区 + 其他. 堆 = Old Space + Young Space. JVM用持久带(Permanent Space)实现方法区,主要存放所有已加载的类信息,方法信息,常量池等等. 可通过-XX:PermSize和-XX:MaxPermSize来指定持久带初始化值和最大值.
- 互联网 - ITeye博客
1、 内存溢出的原因是什么.
内存溢出是由于没被引用的对象(垃圾)过多造成JVM没有及时回收,造成的内存溢出. 如果出现这种现象可行代码排查:.
一)是否App中的类中和引用变量过多使用了Static修饰 如public staitc Student s;在类中的属性中使用 static修饰的最好只用基本类型或字符串.
- 互联网 - ITeye博客
虽然jvm可以通过GC自动回收无用的内存,但是代码不好的话仍然存在内存溢出的风险. 最近在网上搜集了一些资料,现整理如下:. 一、为什么要了解内存泄露和内存溢出. 1、内存泄露一般是代码设计存在缺陷导致的,通过了解内存泄露的场景,可以避免不必要的内存溢出和提高自己的代码编写水平;. 2、通过了解内存溢出的几种常见情况,可以在出现内存溢出的时候快速的定位问题的位置,缩短解决故障的时间.
- Java - 编程语言 - ITeye博客
相信通过写java程序讨生活的人对内存溢出并不陌生,如下文字的出现更是让人恼火:. 尤其当应用服务器(Java容器)出现上述情况更是让人有一种天塌下来的感觉.
好的编码实践可能会大大降低内存溢出的产生.
本文并不是写如何规避内存溢出,但是我还是要介绍一下如何能够尽量规避内存溢出:. 找几个资深程序猿(或者整个项目组讨论后)写一个Java编码规范,让项目组成员尽量遵守.
- 研发管理 - ITeye博客
垃圾回收是Java程序员了解最少的一部分. 他们认为Java虚拟机接管了垃圾回收,因此没必要去担心内存的申请,分配等问题. 但是随着应用越来越复杂,垃圾回收也越来越复杂,一旦垃圾回收变的复杂,应用的性能将会大打折扣. 所以,Java程序员了解垃圾回收的机制并且知道怎样解决“内存溢出”问题会有很大的益处.
- Java - 编程语言 - ITeye博客
前段时间基于OpenJms部署了一个消息中间件服务器,通过主题订阅模式在各个消息节点之间传递信息,但是某个类型的消息节点长时间运行后出现了内存溢出问题,最后使用JProfiler的基本线程监测功能找到问题所在,并且进行解决. Java 版本 java version &1.7.0_40&.
- ITeye博客
堆(Heap)又被称为:优先队列(Priority Queue),是计算机科学中一类特殊的数据结构的统称. 堆通常是一个可以被看做一棵树的数组对象. 在队列中,调度程序反复提取队列中第一个作业并运行,因而实际情况中某些时间较短的任务将等待很长时间才能结束,或者某些不短小,但具有重要性的作业,同样应当具有优先权.
- Java - 编程语言 - ITeye博客
(问题一:什么叫垃圾回收机制. ) 垃圾回收是一种动态存储管理技术,它自动地释放不再被程序引用的对象,按照特定的垃圾收集算法来实现资源自动回收的功能. 当一个对象不再被引用的时候,内存回收它占领的空间,以便空间被后来的新对象使用,以免造成内存泄露. (问题二:java的垃圾回收有什么特点. ) JAVA语言不允许程序员直接控制内存空间的使用.
- hikerlive - ITeye论坛最新精华讨论帖
笔者最近在做一个类SNS的项目,其中使用了MongoDB进行Feed信息存储,并使用定时器删除过期信息.
定时器的时间变量为60天,设定.
在项目上线的某天,突然发现,2周前的数据丢失了,遍历了程序,没发现逻辑问题,甚至开始当心MongoDB造成的数据丢失(业内也是发生过的).
- ITeye博客
JAVA的垃圾回收机制,让许多程序员觉得内存管理不是很重要,但是内存内存泄露的事情恰恰这样的疏忽而发生,特别是对于Android开发,内存管理更为重要,养成良好的习惯,有利于避免内存的泄漏..
这里可以把许多对象和引用看成是有向图,顶点可以是对象也可以是引用,引用关系就是有向边.
坚持分享优质有趣的原创文章,并保留作者信息和版权声明,任何问题请联系:@。5810人阅读
C/C++(46)
Linux(9)
本文是《一种定位内存泄露的方法(Solaris)》对应的Linux版本,调试器使用gdb。主要介绍实例部分。其他请见《一种定位内存泄露的方法(Solaris)》。
模拟new失败的程序:
#include &stdexcept&
&&&&&&& virtual ~ABC(){}
&&&&&&& for (int i = 0; i & 1000; ++i)
&&&&&&&&&&&&&&& ABC* p = new ABC;
&&&&&&& throw std::bad_alloc();
int main()
&&&&&&& f();
&&&&&&& return 0;
1)编译运行此段代码。产生一个core文件
2)用gdb打开这个core文件:
gdb a.out core
Starting program: /test/new_fail/a.out
terminate called after throwing an instance of 'std::bad_alloc'
& what():& std::bad_alloc
Program received signal SIGABRT, Aborted.
0x00007ffff733f645 in raise () from /lib64/libc.so.6
(gdb) info proc
process 10683
cmdline = '/test/new_fail/a.out'
cwd = '/test/new_fail'
exe = '/test/new_fail/a.out'
(gdb) shell pmap 10683
10683: a.out
START&&&&&&&&&&&&&& SIZE&&&& RSS&&&& PSS&& DIRTY&&& SWAP PERM MAPPING
0000&&&&& 4K&&&&& 4K&&&&& 4K&&&&& 0K&&&&& 0K r-xp /test/new_fail/a.out
0000&&&&& 4K&&&&& 4K&&&&& 4K&&&&& 4K&&&&& 0K r--p /test/new_fail/a.out
1000&&&&& 4K&&&&& 4K&&&&& 4K&&&&& 4K&&&&& 0K rw-p /test/new_fail/a.out
2000&&& 132K&&&& 32K&&&& 32K&&&& 32K&&&&& 0K rw-p [heap]
Total:&&&&&&&&&&& 11468K&& 1048K&&& 684K&&& 180K&&&&& 0K
360K writable-private, 11108K readonly-private, 0K shared, and 1048K referenced
可以看到heap空间的起始地址是0x2000,共132K字节,即132*字节。
3)因为是64位应用程序,所以指针占8字节。所以需要遍历的指针个数为=16896。
4)将结果输出到日志文件gdb.txt中:
(gdb) set height 0
(gdb) set logging on
Copying output to gdb.txt.
(gdb) x/10
gdb.txt的内容:
0x602000:&&&&&& 0x0&&&& 0x21
0x602010:&&&&&& 0x400b30 &_ZTV3ABC+16&& 0x0
0x602020:&&&&&& 0x0&&&& 0x21
0x602030:&&&&&& 0x400b30 &_ZTV3ABC+16&& 0x0
5)过滤gdb.txt:
awk '{print $2"/n"$3}' gdb.txt|c++filt|grep vtable&gdb_vtable.txt
gdb_vtable.txt的内容为:
&vtable for ABC+16&
&vtable for ABC+16&
&vtable for ABC+16&
&vtable for ABC+16&
6)将gdb_vtable.txt的内容导入到SQLServer中(如果记录不多,可以用Excel代替)。表名为gdb_vtable,第一列Col001为符号。对其分组求和:
select Col001, count(1) quantity from gdb_vtable
group by Col001
order by quantity desc
Col001&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&quantity
&vtable for ABC+16&&&&&& &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& &&&&&&&& 1000
&vtable for std::bad_alloc@@GLIBCXX_3.4+16&&&&&&&&&&&&&&&& 1
可知core里有1000个ABC,遍历使用ABC的代码,可知存在泄漏。
参考知识库
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
访问:165319次
积分:2849
积分:2849
排名:第8400名
原创:105篇
转载:10篇
评论:62条
(5)(2)(1)(1)(1)(2)(1)(2)(1)(3)(4)(3)(2)(2)(1)(1)(1)(1)(1)(3)(5)(3)(1)(1)(1)(1)(10)(9)(6)(5)(5)(29)(1)求救 定位代码中的内存泄露位置_c++吧_百度贴吧
&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&签到排名:今日本吧第个签到,本吧因你更精彩,明天继续来努力!
本吧签到人数:0成为超级会员,使用一键签到本月漏签0次!成为超级会员,赠送8张补签卡连续签到:天&&累计签到:天超级会员单次开通12个月以上,赠送连续签到卡3张
关注:229,375贴子:
求救 定位代码中的内存泄露位置收藏
有没有什么工具阿,一个项目的代码,要检查内存泄露,有没有什么工具,我用的是vs2010。谢谢。
福利不只是穿多穿少,还要有迷人的微笑!
可以用Visual Leak Detector。
直接用MSVC自带的_CrtDumpMemoryLeaks就行, 如果要求不高的话.
登录百度帐号推荐应用
为兴趣而生,贴吧更懂你。或

我要回帖

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

 

随机推荐