简体   繁体   English

Java GC的异常行为或内存泄漏?

[英]Java GC strange behaviour or memory leak?

I am working on a Swing application and recently, I started to see the following problem: 我正在使用Swing应用程序,最近,我开始看到以下问题:

I have to display in a separate window a very large job report. 我必须在单独的窗口中显示非常大的工作报告。 I close this window, then I re-open the same job report and I get an OutOfMemory Java heap space error. 关闭此窗口,然后重新打开相同的作业报告,并收到OutOfMemory Java堆空间错误。

The JVM is started with -Xmx512m and all the objects that are created when I open the job report take about 300MB on heap. JVM以-Xmx512m启动,当我打开作业报告时创建的所有对象占用大约300MB的堆空间。 Assuming that there isn't a memory leak, I would expect that the second time I open the same job report the JVM won't throw the OOM. 假设没有内存泄漏,我希望第二次打开同一作业报告时,JVM不会抛出OOM。 But, looking at the GC logs after closing the first window, I don't see any GC activity. 但是,在关闭第一个窗口后查看GC日志,我看不到任何GC活动。

The strange thing is that after I close the first window, if I take a heap dump with jmap (without the "live" option) the objects can still be seen in the heap dump. 奇怪的是,在关闭第一个窗口之后,如果我使用jmap进行堆转储(不带“ live”选项),则仍然可以在堆转储中看到对象。

If I run jmap with the dump:live option, the followings happen: 如果我使用dump:live选项运行jmap,则会发生以下情况:

  • after the first heap dump is taken, I can still see the objects on the heap. 进行第一个堆转储后,我仍然可以看到堆上的对象。
  • when I take the second heap dump, it no longer contains those objects, I can re-open the same job report again, with no problems. 当我进行第二个堆转储时,它不再包含那些对象,我可以再次重新打开相同的作业报告,而没有任何问题。 So, if it was a memory leak, then those objects could not have been collected, am I right? 因此,如果是内存泄漏,则无法收集那些对象,对吗?

I tested this on Java 6 (1.6.0_25 ad 1.6.0_45, on Windows) and it reproduces all the time. 我在Java 6(在Windows上为1.6.0_25和1.6.0_45,在Windows上)中对此进行了测试,并且该代码一直在再现。

Running jmap -heap prints : 运行jmap -heap打印:

"using thread-local object allocation.
Mark Sweep Compact GC

Heap Configuration:
   MinHeapFreeRatio = 40
   MaxHeapFreeRatio = 70
   MaxHeapSize      = 536870912 (512.0MB)
   NewSize          = 1048576 (1.0MB)
   MaxNewSize       = 4294901760 (4095.9375MB)
   OldSize          = 4194304 (4.0MB)
   NewRatio         = 2
   SurvivorRatio    = 8
   PermSize         = 12582912 (12.0MB)
   MaxPermSize      = 134217728 (128.0MB)

"

JVM is started with the following options: JVM使用以下选项启动:

"   -Xms128m
    -Xmx512m
    -XX:MaxPermSize=128M
    -verbose:gc
    -XX:+PrintGCTimeStamps
    -XX:+PrintGCDetails
    -Xloggc:c:\my_gc.log
    -XX:+HeapDumpOnOutOfMemoryError"

So, my question is: why are all the objects collected when I take the heap dump with the live option (a sign that there isn't a memory leak) but, if I don't do this, I am unable to re-open another(or the same) job report because I get an OOM error? 因此,我的问题是:为什么在使用live选项进行堆转储时会收集所有对象(这表明没有内存泄漏),但是,如果我不这样做,我将无法重新打开另一个(或相同)作业报告,因为我收到OOM错误?

Also, I tested another scenario: 另外,我测试了另一种情况:

  • open the first job report window, then closed it. 打开第一个作业报告窗口,然后将其关闭。
  • created a menu item that when pressed, creates in an infinite loop Long instances until the JVM throws an OOM. 创建了一个菜单项,该菜单项在按下时会无限循环地创建Long实例,直到JVM抛出OOM为止。 I inspected the heap dump that was generated when the OOM was thrown and the heap was filled 99% with Long instances and none of my job report objects were on the heap. 我检查了引发OOM时生成的堆转储,并且该堆用Long实例填充了99%,并且我的作业报告对象都不在堆上。

Thanks in advance. 提前致谢。

So, my question is: why are all the objects collected when I take the heap dump with the live option 所以,我的问题是:为什么在使用live选项进行堆转储时,为什么要收集所有对象?

The jmap live option forces a collection. jmap live选项强制收集。 It has been discussed here . 这里已经讨论过

Your observations corroborate that. 您的观察证实了这一点。

What can be done as an exercise is re-opening the window post some GC activity to see whether the memory has been reclaimed. 练习后可以做些什么,就是在某些GC活动之后重新打开窗口,以查看是否已回收内存。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM