Java 连续2个完整GC周期中未清除内存

Java 连续2个完整GC周期中未清除内存,java,garbage-collection,jvm,java-7,Java,Garbage Collection,Jvm,Java 7,我无法理解垃圾收集器在这里做什么,我可以看到3个完整的GC周期,只有第一个周期清除了一些内存,其他2个周期内存没有清除,但每个周期需要16秒 1189.994: [GC1189.994: [ParNew: 446787K->22515K(471872K), 0.1136668 secs] 1408852K->990343K(4141888K), 0.1144236 secs] [Times: user=0.87 sys=0.01, real=0.11 secs] 1204.825:

我无法理解垃圾收集器在这里做什么,我可以看到3个完整的GC周期,只有第一个周期清除了一些内存,其他2个周期内存没有清除,但每个周期需要16秒

1189.994: [GC1189.994: [ParNew: 446787K->22515K(471872K), 0.1136668 secs] 1408852K->990343K(4141888K), 0.1144236 secs] [Times: user=0.87 sys=0.01, real=0.11 secs] 
1204.825: [Full GC1204.826: [CMS: 967828K->695710K(3670016K), 20.8721088 secs] 1192388K->695710K(4141888K), [CMS Perm : 133862K->133237K(524288K)], 20.8732268 secs] [Times: user=20.81 sys=0.13, real=20.87 secs] 
1225.703: [Full GC1225.703: [CMS: 695710K->695710K(3670016K), 16.7364748 secs] 695716K->695710K(4141888K), [CMS Perm : 133237K->133237K(524288K)], 16.7373018 secs] [Times: user=16.77 sys=0.01, real=16.74 secs] 
1242.444: [Full GC1242.444: [CMS: 695710K->695710K(3670016K), 16.4691631 secs] 695727K->695710K(4141888K), [CMS Perm : 133237K->133237K(524288K)], 16.4698573 secs] [Times: user=16.51 sys=0.02, real=16.47 secs] 
1283.740: [GC1283.741: [ParNew: 419456K->33117K(471872K), 0.1520895 secs] 1115166K->728827K(4141888K), 0.1531085 secs] [Times: user=1.06 sys=0.01, real=0.15 secs]
每天我都会在gc.log和中看到这一点,每次2个循环都没有用

vm参数为

java -server -Xms4096m -Xmx4096m -XX:PermSize=512m
-XX:MaxPermSize=512m -XX:MaxNewSize=512m -XX:+UseConcMarkSweepGC -XX:+CMSClassUnloadingEnabled -XX:+UseMembar -d64 -verbose:gc -XX:+PrintGCDetails -XX:+PrintGCTimeStamps -Xloggc:GC.log -classpath ......
可用处理器核数:16

编辑:
我考虑删除MaxNewSize参数,因为它现在是整个堆的1/8。我在几篇文章中读到它应该是总堆的1/3到1/4。但我无法正确解释年轻一代的大小MaxNewSize将如何影响GC

听起来这些对象仍然处于活动状态,并且仍然有指向它们的链接。您可以通过在声明和初始化对象/变量的位置移动来解决这个问题。这并不总是可能的,因为它可能会影响程序的运行。请记住,垃圾收集并不总是释放空间,它只释放可以释放的空间


你认为应该释放空间有什么原因吗?您是手动触发垃圾收集器,还是只是自动运行垃圾收集器

查看GC日志,我几乎没有想到什么

在这种情况下,旧的10位内存的容量不超过3 GB,但已满695 MB。那么为什么GC会触发呢?GC循环很少运行,但不从perm或旧版本收集任何东西。这可能是由于手动触发的原因吗?请记住,当旧的gen堆存在碎片时,完整GC将运行,因此升级很困难,或者InitiatingHeapOccupencyPercent设置得太低。对于某些JVM,默认值为45。您可以将其设置为-XX:+InitiatingHeapOccupencyPercent=70
也许程序没有做太多的事情,内存中的所有东西都是静态的,不会被GCD吗?@Steve如果是这样的话,为什么要启动完整的gc,你看应用程序在这段时间里被卡住了。看起来你有内存泄漏。使用诸如MAT或Yourkit之类的探查器来分析内存转储并检测可能的泄漏。@LuiggiMendoza您能否解释一下您感觉内存泄漏的原因,我看不到使用了多少内存,为此我将更改一些参数,以便停止频繁的GC。在两个完整的GC周期后,没有任何内容被释放,看起来你总是在使用你创建的所有对象,即使你不需要它们,因此它们应该被删除。但这可能只是一个猜测。此日志来自我的测试环境,当我使用工具时,大约有50人在使用此应用程序。如果没有什么可以释放的,为什么java会完整启动3次?有一些事情会导致GC运行。首先,有些人可能需要手动运行它。您是否编写了所有有问题的代码?是否包含任何手动运行?GC也会在几代中存储东西,并进行一些内存压缩,因此它可能会触发以完成其中一个操作。我不知道GC的复杂细节,但我猜有些情况可能会导致它运行而不删除任何内容。看看这里,可以看到更多关于GC的信息,即使我们有system.GC调用,我们也不会强制jvm。JVM在gc调用后决定是否运行。这里JVM正在运行3个周期,其中2个是无用的。我觉得这是我的虚拟机参数,迫使这种行为。