当我运行下面的JUnit测试时,java进程的内存不断增加。几个小时后,它使用了2go以上。但是,当我用jvisualvm查看时,堆和permgen大小是稳定的,我没有看到任何泄漏。测试是用-Xmx32m
运行的
public class TestCat {
public static class A { }
@Test
public void testCategory() {
for(;;) {
GroovyCategorySupport.use(A.class, new Closure<Object>(null) {
public Object call() { return null; }
});
}
}
}
我已经用Groovy 2.4.7、Windows和JRE1.7_80、MacOS和JRE1.7_60测试过了。我无法用MacOS和JRE 1.8.0_91重现此错误
我认为这与JRE1.7中的一个bug有关,我正在寻找一种方法来缓解这个问题:
- 我的测试可能是错误的?2怎么可能泄漏“系统”内存而不泄漏堆空间或permgen空间?
- 这是Groovy和JRE 1.7之间的“已知”错误还是不兼容?
- 如何使用groovy category和一个1.7的jre,而不遭受这种内存泄漏?
编辑
我可以通过调用VMPluginFactory.getPlugin().invalidateCallSites()
来重现这个bug,它可以翻译成这个“纯java”单元测试:
public class TestSwitchPoint {
@Test
public void testSP() {
SwitchPoint switchPoint = new SwitchPoint();
for(;;) {
SwitchPoint old = switchPoint;
switchPoint = new SwitchPoint();
SwitchPoint.invalidateAll(new SwitchPoint[]{old});
}
}
}
实际上,只需要new SwitchPoint()
就足够了。
1条答案
按热度按时间7qhs6swi1#
是的,JRE中有一个bug。本机内存泄漏发生在JVM内部的以下位置:
这是MemberNameTable的已知问题:JDK-8152271。不幸的是,仅在JDK 9中修复了该问题。幸运的是,由于在JDK-8050166中完成了MethodHandles重构,因此在JDK 8中不会出现该问题。尽管MemberNameTable问题仍然存在,但
SwitchPoint()
不再创建新的MemberName。后一个修复也已后移植到JDK 7u91。如果Groovy运行时检测到Java 7+,它将使用MethodHandles。您可以通过修补
VMPluginFactory
以使用Java 6插件来解决此问题。下面是patch。如果包含在Groovy库之前的类路径中,它将强制Groovy运行时使用Java 6兼容的VMPlugin。因此,您可以使用以下选项来解决内存泄漏问题: