Java GC奇怪的行为还是内存泄漏?

时间:2013-04-28 10:30:59

标签: java garbage-collection heap memory-leaks out-of-memory

我正在研究Swing应用程序,最近,我开始看到以下问题:

我必须在一个单独的窗口中显示一份非常大的工作报告。我关闭此窗口,然后重新打开相同的作业报告,我收到OutOfMemory Java堆空间错误。

JVM以-Xmx512m启动,打开作业报告时创建的所有对象在堆上占用大约300MB。假设没有内存泄漏,我希望第二次打开相同的作业报告时JVM不会抛出OOM。但是,在关闭第一个窗口后查看GC日志,我看不到任何GC活动。

奇怪的是,在关闭第一个窗口后,如果我使用jmap进行堆转储(没有“live”选项),仍然可以在堆转储中看到对象。

如果我使用dump:live选项运行jmap,则会发生以下情况:

  • 在第一次堆转储后,我仍然可以看到堆上的对象。
  • 当我进行第二次堆转储时,它不再包含这些对象,我可以再次重新打开相同的作业报告,没有任何问题。 所以,如果是内存泄漏,那么这些对象就无法收集,我是对的吗?

我在Java 6(1.6.0_25 ad 1.6.0_45,Windows上)上进行了测试,并且它一直在重现。

运行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使用以下选项启动:

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

所以,我的问题是:为什么在我使用live选项进行堆转储时收集了所有对象(没有内存泄漏的迹象)但是,如果我不这样做,我就无法重新打开另一个(或相同的)工作报告,因为我收到OOM错误?

另外,我测试了另一个场景:

  • 打开第一个作业报告窗口,然后关闭它。
  • 创建了一个菜单项,按下后,在无限循环中创建Long实例,直到JVM抛出OOM。 我检查了在抛出OOM时生成的堆转储,并且使用Long实例填充了99%的堆,并且没有任何作业报告对象在堆上。

提前致谢。

1 个答案:

答案 0 :(得分:1)

  

所以,我的问题是:为什么我拿走时会收集所有对象   使用实时选项的堆转储

jmap实时选项强制收集。已经讨论过here

您的观察证实了这一点。

作为练习可以做的是重新打开一些GC活动的窗口以查看内存是否已被回收。