`
jinyanhui2008
  • 浏览: 312139 次
  • 性别: Icon_minigender_1
  • 来自: 青岛
社区版块
存档分类
最新评论

关于java堆栈溢出的那些事

    博客分类:
  • Java
阅读更多

java.lang.OutOfMemoryError: Java heap space

在java程序运行中可能会报如上的错误,通常是在运行过程中内存占用了没有别释放造成的。

以前可能没法跟踪可能是很痛苦的事情,现在好了,我们有一个调试软件可以用了,在生产环境下使用的jRockit软件进行调试,是oracle公司出品的。

前两天试用了一下真的很不错。

前阵子有个程序跑2个礼拜左右就会堆栈溢出,始终找不到头绪,后来使用jrockit才找到问题的出处。

jrockit是可以调试远程程序也可以调试本地程序的。

具体调试步骤

(一)

启动调试程序

 

如果是调试本地程序的话,启动jrockit,然后启动本地需要调试的程序,会在左侧工具栏 本地目录下创建一个连接为需要调试的程序,在上面点击右键,就会启动跟踪。

如何跟踪呢,我的办法就是等,在跟踪开始后,进行截图,然后等程序运行一段时间后查找堆增长比较大的并且一直没有释放的变量。

(二)

然后在上面点击右键,显示分配跟踪。

(三)

然后找到对应的方法,然后就去找问题吧,看看是不是那个地方有内存一直没有释放啊。

 

然后说点我自己的小经验,也许是不对的,但是我在我的应用里面确实是有效的。

 

在经常需要调用的地方将变量设成全局的甚至是静态的,我的操作是设成全局的了。图省事呢。呵呵,因为我的变量时全局都要调用的而且是频繁调用的。

用完的变量一定要记得让它等于null,否则执行gc()貌似是不给回收的。

基本上jrockit跟踪是很强的,都能够找到你的问题所在,要仔细观察,改完程序后记得再重新跟踪下直到没有内存泄露为止。

写完手工。

题外话,写多线程的时候建议使用线程池来操作。

分享到:
评论
48 楼 凤舞凰扬 2009-09-21  
jinyanhui2008 写道
凤舞凰扬 写道
ZangXT 写道
jinyanhui2008 写道
那么在执行完了之后,如果stack中不为空的时候,将stack置为null,是否也会清空内存呢?

会的。
看一下根集的相关概念。

   这段代码看得出是在方法体内部。如果是这样的话,不管你设置stack为null与否(因为stack没有被外部所引用),在执行完,进行MinorGC就会回收的。去在一个方法中设置局部变量为null是多余并且妨碍阅读的做法。

哦,可能没有问清楚,我想问的是stack为全局变量的情况下。如果将stack=null,是否会清空啊?或者如果在全局变量下不将stack=null是否会在类调用完成后清空呢?

    你应该这样理解。当你把stack设置为null的时候,也就是你当前对象不存在对stack对象的引用,这样的话,也就降低了stack对象被根引用的可能性(比如说你当前对象存在根引用,那么它所引用的对象也不会被回收)。如果你的stack对象是在当前对象内创建的,如果没有传递到外部,那么它就会在GC时回收。(其实这里有一个比较的情况,也就是你当前对象如果也能确保不被根引用,那么去设置stack = null其实是多余的了,因为它会同当前对象一起在GC时回收。)
47 楼 youngJiang 2009-09-16  
一直想找一个这样的工具,这下可好了,谢谢楼主
46 楼 andy54321 2009-09-14  
NetBeans提供类似的内存监控功能,界面也有些相似;
JDK自带的JConsole也可辅助
45 楼 ZangXT 2009-09-12  
http://developers.sun.com/learning/javaoneonline/2007/pdf/TS-2906.pdf
44 楼 jinyanhui2008 2009-09-12  
凤舞凰扬 写道
ZangXT 写道
jinyanhui2008 写道
那么在执行完了之后,如果stack中不为空的时候,将stack置为null,是否也会清空内存呢?

会的。
看一下根集的相关概念。

   这段代码看得出是在方法体内部。如果是这样的话,不管你设置stack为null与否(因为stack没有被外部所引用),在执行完,进行MinorGC就会回收的。去在一个方法中设置局部变量为null是多余并且妨碍阅读的做法。

哦,可能没有问清楚,我想问的是stack为全局变量的情况下。如果将stack=null,是否会清空啊?或者如果在全局变量下不将stack=null是否会在类调用完成后清空呢?
43 楼 zozoh 2009-09-11  
这个贴有意思,哈哈
42 楼 凤舞凰扬 2009-09-10  
ZangXT 写道
jinyanhui2008 写道
那么在执行完了之后,如果stack中不为空的时候,将stack置为null,是否也会清空内存呢?

会的。
看一下根集的相关概念。

   这段代码看得出是在方法体内部。如果是这样的话,不管你设置stack为null与否(因为stack没有被外部所引用),在执行完,进行MinorGC就会回收的。去在一个方法中设置局部变量为null是多余并且妨碍阅读的做法。
41 楼 ZangXT 2009-09-10  
jinyanhui2008 写道
那么在执行完了之后,如果stack中不为空的时候,将stack置为null,是否也会清空内存呢?

会的。
看一下根集的相关概念。
40 楼 jinyanhui2008 2009-09-10  
C_J 写道
谢楼上的提醒

-static是类加载的时候申请的空间,同时static{}静态模块也是触发了类加载才做的动作;

-head确实是个笔误,呵呵~

-已在原贴更正,见原帖;

以下的代码的 stack=null, 改为  o=null
Stack stack=new Stack();
for(...)
{
Object o=new Object();
stack.push(o);
//stack=null; 改为o=null;谢谢大家的提醒;
o=null;
}

其中o这些对象是不会被GC回收的~

那么在执行完了之后,如果stack中不为空的时候,将stack置为null,是否也会清空内存呢?
39 楼 C_J 2009-09-09  
谢楼上的提醒

-static是类加载的时候申请的空间,同时static{}静态模块也是触发了类加载才做的动作;

-head确实是个笔误,呵呵~

-已在原贴更正,见原帖;

以下的代码的 stack=null, 改为  o=null
Stack stack=new Stack();
for(...)
{
Object o=new Object();
stack.push(o);
//stack=null; 改为o=null;谢谢大家的提醒;
o=null;
}

其中o这些对象是不会被GC回收的~
38 楼 ZangXT 2009-09-09  
<div class="quote_title">hsbljyy 写道</div>
<div class="quote_div">那您能不能解释一下什么是堆,什么是栈?</div>
<p><br>可以看这个:<a href="http://zangxt.iteye.com/admin/blogs/440330">http://zangxt.iteye.com/admin/blogs/440330</a></p>
<p>不过我写的比较晦涩,可能看起来会有点累。</p>
37 楼 ZangXT 2009-09-09  
C_J 写道
完全错误?
1、static静态数据在加载JVM就初始化并分配存储空间;
基本数据类型存储在内存静态区
如:
public static int tmp;
对象数据类型可能在head区
像楼上说的"static变量所引用的对象是会可能在Heap中的"
如:
public static Singleton instance=new Singleton();

2、可以说new出来的空间都存储在head中,而栈中的变量在栈退出的时候就释放掉了。

3、GC的回收应该是这块head区域没有被引用了才自动释放,但是要注意类似如下情况:

Stack stack=new Stack();
for(...)
{
Object o=new Object();
stack.push(o);
}
stack=null;
其中o这些对象是不会被GC回收的~


1.static静态数据不是加载jvm时初始化,而是加载类的时候分配空间并初始化。空间分配在PermGen。这个前面已经有人讲了。
当然你也可以把PermGen叫做堆,不过也有说法称之为“非堆”,因为Class的信息,字符串常量池都在这里面。跟我们平时说的堆还是有所不同的。
public static Singleton instance=new Singleton();
这个instance变量肯定是在PermGen的,但是它引用的对象首先在young区分配内存,当然可能随着年龄的增长,对象也可能被移动到PermGen中。
2.head是heap的笔误?
3.实在看不明白这个例子。stack=null之后,原来在stack中的对象已经没有任何从根集出发的引用可达了,怎么可能不被回收呢?
36 楼 hsbljyy 2009-09-09  
<div class="quote_title">hsbljyy 写道</div>
<div class="quote_div">
<div class="quote_title">ZangXT 写道</div>
<div class="quote_div">
<div class="quote_title">hsbljyy 写道</div>
<div class="quote_div">
<div class="quote_title">凤舞凰扬 写道</div>
<div class="quote_div">
<div class="quote_title">hsbljyy 写道</div>
<div class="quote_div">
<div class="quote_title">jinyanhui2008 写道</div>
<div class="quote_div">
<p>在经常需要调用的地方将变量设成全局的甚至是静态的,我的操作是设成全局的了。图省事呢。呵呵,因为我的变量时全局都要调用的而且是频繁调用的。</p>
<p>用完的变量一定要记得让它等于null,否则执行gc()貌似是不给回收的。</p>
</div>
<p><br>不是很明白你这句话中的全局变量指的是什么。如果指的是对象范围内的全局变量,那么在这个对象没有被外部引用的时候,gc应该会处理好这些关系。没有被gc回收的原因肯定是你这个变量指向的对象还存在其他的引用,用static修饰的也一样,除非你用的是static final修饰。</p>
<p> </p>
</div>
<p>    一般来说,全局变量指的就是类的可变属性,也就是你所说的对象范围内的全局变量。同时纠正一点,static的变量是存储在PermGen空间中,而不是heap中(当然了,static变量所引用的对象是会可能在Heap中的),PermGen过大也会超出内存溢出的错误。并且static变量引用的对象属于根引用的序列中,所以即使没有了任何其他引用,一样不会被GC回收,所以你举的这个例子是不对的。</p>
</div>
<p><br>可能是我没有说清楚吧,造成了误会,不好意思。据我所知,对象创建完一般是放在堆中的,也就是你说的heap,static的变量的确是存放在栈当中,一般来说,只要jvm加载了class后,static修饰的变量就会放在栈当中,一般不会被jvm的GC回收。</p>
<p> </p>
<p>我说的“用static修饰的也一样”,指的是修饰的变量所指向的对象,是我没有表述清楚,造成了误会,实在是抱歉。</p>
<p> </p>
<p>就像你说的,栈存放的东西过多也会内存溢出,呵呵,不过我还没碰到过这样的事情。</p>
<p> </p>
<p>据说栈的速度比堆的速度快(貌似是算法决定的,堆比较灵活,但牺牲了速度;而栈刚好相反;是不是这样我不知道,没经过测试。),但貌似栈的内存空间比较小,所以如果放置了太多东西,就容易出现内存溢出。</p>
<p> </p>
<p>这些都是我看到的一些理论知识,没有经过试验,也不知道是否正确,还请各位指点。</p>
</div>
<p><br>先理解一下什么是堆,什么是栈吧。基本完全错误。</p>
</div>
<p>那您能不能解释一下什么是堆,什么是栈?</p>
</div>
<p>刚刚重新温习了下堆和栈的知识,发现我关于static的说法的确有误,敬请原谅。</p>
35 楼 hsbljyy 2009-09-09  
<div class="quote_title">C_J 写道</div>
<div class="quote_div">3、GC的回收应该是这块head区域没有被引用了才自动释放,但是要注意类似如下情况:<br><br><pre name="code" class="java">Stack stack=new Stack();
for(...)
{
Object o=new Object();
stack.push(o);
}
stack=null;
</pre>
其中o这些对象是不会被GC回收的~<br><br>
</div>
<p> </p>
<p>这点不是很理解。按照您这么说,容器类就很容易出现内存溢出?还是我的理解有误?</p>
34 楼 hsbljyy 2009-09-09  
<div class="quote_title">ZangXT 写道</div>
<div class="quote_div">
<div class="quote_title">hsbljyy 写道</div>
<div class="quote_div">
<div class="quote_title">凤舞凰扬 写道</div>
<div class="quote_div">
<div class="quote_title">hsbljyy 写道</div>
<div class="quote_div">
<div class="quote_title">jinyanhui2008 写道</div>
<div class="quote_div">
<p>在经常需要调用的地方将变量设成全局的甚至是静态的,我的操作是设成全局的了。图省事呢。呵呵,因为我的变量时全局都要调用的而且是频繁调用的。</p>
<p>用完的变量一定要记得让它等于null,否则执行gc()貌似是不给回收的。</p>
</div>
<p><br>不是很明白你这句话中的全局变量指的是什么。如果指的是对象范围内的全局变量,那么在这个对象没有被外部引用的时候,gc应该会处理好这些关系。没有被gc回收的原因肯定是你这个变量指向的对象还存在其他的引用,用static修饰的也一样,除非你用的是static final修饰。</p>
<p> </p>
</div>
<p>    一般来说,全局变量指的就是类的可变属性,也就是你所说的对象范围内的全局变量。同时纠正一点,static的变量是存储在PermGen空间中,而不是heap中(当然了,static变量所引用的对象是会可能在Heap中的),PermGen过大也会超出内存溢出的错误。并且static变量引用的对象属于根引用的序列中,所以即使没有了任何其他引用,一样不会被GC回收,所以你举的这个例子是不对的。</p>
</div>
<p><br>可能是我没有说清楚吧,造成了误会,不好意思。据我所知,对象创建完一般是放在堆中的,也就是你说的heap,static的变量的确是存放在栈当中,一般来说,只要jvm加载了class后,static修饰的变量就会放在栈当中,一般不会被jvm的GC回收。</p>
<p> </p>
<p>我说的“用static修饰的也一样”,指的是修饰的变量所指向的对象,是我没有表述清楚,造成了误会,实在是抱歉。</p>
<p> </p>
<p>就像你说的,栈存放的东西过多也会内存溢出,呵呵,不过我还没碰到过这样的事情。</p>
<p> </p>
<p>据说栈的速度比堆的速度快(貌似是算法决定的,堆比较灵活,但牺牲了速度;而栈刚好相反;是不是这样我不知道,没经过测试。),但貌似栈的内存空间比较小,所以如果放置了太多东西,就容易出现内存溢出。</p>
<p> </p>
<p>这些都是我看到的一些理论知识,没有经过试验,也不知道是否正确,还请各位指点。</p>
</div>
<p><br>先理解一下什么是堆,什么是栈吧。基本完全错误。</p>
</div>
<p>那您能不能解释一下什么是堆,什么是栈?</p>
33 楼 C_J 2009-09-09  
完全错误?
我提炼一下我觉得正确的几点;
1、“对象创建完一般是放在堆中的,也就是你说的heap”
2、“栈的内存空间比较小”

其他的几点关于static和GC回收的有问题

我的理解

1、static静态数据在加载JVM就初始化并分配存储空间;(已由楼下的兄弟更正,static变量和static模块是在类加载触发的时候申请的内存空间
都存储在JVM分出来heap中的PermGen区。

2、可以说new出来的空间都存储在head中,而栈中的变量在栈退出的时候就释放掉了。

3、GC的回收应该是这块head区域没有被引用了才自动释放,但是要注意类似如下情况:


以下是以前看到内存泄漏看到的,时间看的太远了,所以写的时候难免疏忽了,不好意思,特在此标识出来;
另外找到了文章的出处:http://www.ibm.com/developerworks/cn/java/l-JavaMemoryLeak/index.html


以下的代码的 stack=null, 改为  o=null
Stack stack=new Stack();
for(...)
{
Object o=new Object();
stack.push(o);
stack=null;// 改为o=null;谢谢大家的提醒;
}
其中o这些对象是不会被GC回收的~

32 楼 ZangXT 2009-09-08  
<div class="quote_title">hsbljyy 写道</div>
<div class="quote_div">
<div class="quote_title">凤舞凰扬 写道</div>
<div class="quote_div">
<div class="quote_title">hsbljyy 写道</div>
<div class="quote_div">
<div class="quote_title">jinyanhui2008 写道</div>
<div class="quote_div">
<p>在经常需要调用的地方将变量设成全局的甚至是静态的,我的操作是设成全局的了。图省事呢。呵呵,因为我的变量时全局都要调用的而且是频繁调用的。</p>
<p>用完的变量一定要记得让它等于null,否则执行gc()貌似是不给回收的。</p>
</div>
<p><br>不是很明白你这句话中的全局变量指的是什么。如果指的是对象范围内的全局变量,那么在这个对象没有被外部引用的时候,gc应该会处理好这些关系。没有被gc回收的原因肯定是你这个变量指向的对象还存在其他的引用,用static修饰的也一样,除非你用的是static final修饰。</p>
<p> </p>
</div>
<p>    一般来说,全局变量指的就是类的可变属性,也就是你所说的对象范围内的全局变量。同时纠正一点,static的变量是存储在PermGen空间中,而不是heap中(当然了,static变量所引用的对象是会可能在Heap中的),PermGen过大也会超出内存溢出的错误。并且static变量引用的对象属于根引用的序列中,所以即使没有了任何其他引用,一样不会被GC回收,所以你举的这个例子是不对的。</p>
</div>
<p><br>可能是我没有说清楚吧,造成了误会,不好意思。据我所知,对象创建完一般是放在堆中的,也就是你说的heap,static的变量的确是存放在栈当中,一般来说,只要jvm加载了class后,static修饰的变量就会放在栈当中,一般不会被jvm的GC回收。</p>
<p> </p>
<p>我说的“用static修饰的也一样”,指的是修饰的变量所指向的对象,是我没有表述清楚,造成了误会,实在是抱歉。</p>
<p> </p>
<p>就像你说的,栈存放的东西过多也会内存溢出,呵呵,不过我还没碰到过这样的事情。</p>
<p> </p>
<p>据说栈的速度比堆的速度快(貌似是算法决定的,堆比较灵活,但牺牲了速度;而栈刚好相反;是不是这样我不知道,没经过测试。),但貌似栈的内存空间比较小,所以如果放置了太多东西,就容易出现内存溢出。</p>
<p> </p>
<p>这些都是我看到的一些理论知识,没有经过试验,也不知道是否正确,还请各位指点。</p>
</div>
<p><br>先理解一下什么是堆,什么是栈吧。基本完全错误。</p>
31 楼 srdrm 2009-09-08  
java6就自带有监视工具
30 楼 hsbljyy 2009-09-08  
<div class="quote_title">凤舞凰扬 写道</div>
<div class="quote_div">
<div class="quote_title">hsbljyy 写道</div>
<div class="quote_div">
<div class="quote_title">jinyanhui2008 写道</div>
<div class="quote_div">
<p>在经常需要调用的地方将变量设成全局的甚至是静态的,我的操作是设成全局的了。图省事呢。呵呵,因为我的变量时全局都要调用的而且是频繁调用的。</p>
<p>用完的变量一定要记得让它等于null,否则执行gc()貌似是不给回收的。</p>
</div>
<p><br>不是很明白你这句话中的全局变量指的是什么。如果指的是对象范围内的全局变量,那么在这个对象没有被外部引用的时候,gc应该会处理好这些关系。没有被gc回收的原因肯定是你这个变量指向的对象还存在其他的引用,用static修饰的也一样,除非你用的是static final修饰。</p>
<p> </p>
</div>
<p>    一般来说,全局变量指的就是类的可变属性,也就是你所说的对象范围内的全局变量。同时纠正一点,static的变量是存储在PermGen空间中,而不是heap中(当然了,static变量所引用的对象是会可能在Heap中的),PermGen过大也会超出内存溢出的错误。并且static变量引用的对象属于根引用的序列中,所以即使没有了任何其他引用,一样不会被GC回收,所以你举的这个例子是不对的。</p>
</div>
<p><br>可能是我没有说清楚吧,造成了误会,不好意思。据我所知,对象创建完一般是放在堆中的,也就是你说的heap,static的变量的确是存放在栈当中,一般来说,只要jvm加载了class后,static修饰的变量就会放在栈当中,一般不会被jvm的GC回收。</p>
<p> </p>
<p>我说的“用static修饰的也一样”,指的是修饰的变量所指向的对象,是我没有表述清楚,造成了误会,实在是抱歉。</p>
<p> </p>
<p>就像你说的,栈存放的东西过多也会内存溢出,呵呵,不过我还没碰到过这样的事情。</p>
<p> </p>
<p>据说栈的速度比堆的速度快(貌似是算法决定的,堆比较灵活,但牺牲了速度;而栈刚好相反;是不是这样我不知道,没经过测试。),但貌似栈的内存空间比较小,所以如果放置了太多东西,就容易出现内存溢出。</p>
<p> </p>
<p>这些都是我看到的一些理论知识,没有经过试验,也不知道是否正确,还请各位指点。</p>
29 楼 moonese 2009-09-07  
以前一直用 Yourkit JProfiler, 可以申请 Evaluation 的 License, 分析性能死锁问题的时候够用了。

现在一般的分析也会用 JDK 自带的 jvisualvm,还是能看到很多信息的,使用也很方便,而且免费,不用找xxx,呵呵。

vinter 写道
我一直在用JProfiler,感觉挺好用的,

相关推荐

Global site tag (gtag.js) - Google Analytics