Java 如何对GC进行单元测试?

Java 如何对GC进行单元测试?,java,junit,garbage-collection,classloader,Java,Junit,Garbage Collection,Classloader,对于一个项目,我们需要一种运行用户脚本的方法,该脚本可以随附加的JAR文件和其他类一起运行 当我想写几个测试以确保普通脚本不会留下任何悬念时,我有什么选择 我特别需要知道:附加jar中的所有类都“卸载”了吗 注意:我不是在寻找一个100%超级防水的解决方案,它适用于从1.0到7的所有Java版本。现在,我只需要比“我不知道”更好。我不会尝试对这个进行单元测试。相反,我将使用-XX:-TraceClassUnloading运行JVM,并查看相关类是否显示在跟踪输出中。最好的选择是确保加载的JAR由

对于一个项目,我们需要一种运行用户脚本的方法,该脚本可以随附加的JAR文件和其他类一起运行

当我想写几个测试以确保普通脚本不会留下任何悬念时,我有什么选择

我特别需要知道:附加jar中的所有类都“卸载”了吗


注意:我不是在寻找一个100%超级防水的解决方案,它适用于从1.0到7的所有Java版本。现在,我只需要比“我不知道”更好。我不会尝试对这个进行单元测试。相反,我将使用-XX:-TraceClassUnloading运行JVM,并查看相关类是否显示在跟踪输出中。

最好的选择是确保加载的JAR由特定的类加载器加载,然后丢弃该类加载器(在丢弃所有对象之后)

至于单元测试卸载,如果使用此选项,则需要扩展测试框架和自定义类加载器,以具有“按需创建类加载器”标志。然后在打开标志的情况下加载类一次,放弃类装入器,并在关闭标志的情况下再次尝试加载类。如果该类确实不可访问,则第二次尝试应引发“未找到类”异常。然后,如果单元测试陷入异常,则包装单元测试以通过,如果在第二次加载尝试后成功命中,则包装单元测试以失败


如果您打算使用的不仅仅是纯Java工具,那么可以考虑使用OSGi容器。大多数已建立的OSGi容器实现都显式地测试类卸载。

这完全取决于您允许脚本运行的方式。他们有权访问应用程序其余部分的类吗

Java中泄漏内存的典型方法是使用静态引用。静态引用仅在包含它的类的类加载器中是静态的。因此,如果您使用自己管理的类加载器加载您的用户脚本(并且您无论如何都应该这样做),那么只要您的类加载器本身完成了它,其中的引用(静态或非静态)就可以为GC提供

他们解决这个问题的唯一方法是将对他们的一个对象的引用添加到您的一个对象中。因此,您必须非常小心您公开的API。另一种方法是,如果他们从另一个类加载器在类中对自己的类进行静态引用


我看不到一种完全自动化测试的方法。但是我想您可以使用任何合适的探查器来跟踪类的卸载。

看起来您想要测试的是hose脚本没有


为此,我将创建一个
WeakReference
到用于加载JAR的
ClassLoader
,然后运行脚本,然后调用
System.gc()
,然后调用
assertNull(reference.get())

为什么要卸载它们?你是说它们的实例将被GCed,即用户脚本的代码和库没有内存泄漏吗?你正在用新的类加载器加载它们吗?是的。我想要的是一种询问GC“您现在可以GC这个实例吗?”或者“告诉我有多少引用存在于instance
foo
”探查器是如何做的?第二个选项+1。为了100%确定(我知道这不是要求),您可能需要使用安全管理器运行类加载器(以确保脚本不会创建线程等)。@Sean Reilly,谢谢。其他选项变成了噪音,所以我把消息移到了最上面。问题的关键似乎是Aaron已经在做你在第一段中描述的事情了,但是因为你不能显式地丢弃Java对象,所以他想要一种方法来检查它是否真的隐式发生,或者是否存在泄漏。@Michael Borgwardt,自定义类加载器负责构造所有对象,因此它可以感知(在其域中)创建的所有对象。使这些链接成为弱引用,在关闭类加载器时调用垃圾收集,如果还有任何被引用的对象,类加载器可以报告它。这仍然不是单元测试;这听起来更像是试图将类加载器设计推进测试团队。@MichaelBorgwardt,对不起。手边没有代码,但首先要建立一个地图来保存所有代码。然后使用类似ASM的方法将“对象注册”添加到类构造函数中,让对象检查是否在构建时由“可注册”的加载程序加载,如果是,则检查“注册”本身。记住在“从这个类加载器映射创建的对象”中使用弱引用,否则您将面临一次令人印象深刻的内存泄漏!我将在今晚的聚会上讨论这个想法。要做到这一点应该不太难,但要做到“正确”要稍微难一些。另一种方法可能是为每个JAR创建一个URLClassLoader实例,并使用它来加载类。一旦完成,就将其丢弃(设置为null)。@aishwarya:这根本不是“替代方案”。您不能“丢弃”java对象。将引用设置为null仅允许在没有其他引用的情况下对对象进行垃圾收集。我描述的是如何测试对象实际上是垃圾收集的。众所周知,类加载器很难摆脱,因为对隐藏在集合somwhere中的任何加载类的一个对象的引用足以防止类加载器和通过它加载的所有类被垃圾收集。