Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/368.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
验证Java中的对象删除_Java_Unit Testing_Testing_Garbage Collection - Fatal编程技术网

验证Java中的对象删除

验证Java中的对象删除,java,unit-testing,testing,garbage-collection,Java,Unit Testing,Testing,Garbage Collection,在我的代码中,有许多在运行时创建和删除的对象,它们可能有很长的引用链(也就是说,可以从许多地方进行垃圾收集) 在我的单元测试中,我想验证当我“删除”一个对象时,例如从主要包含它的列表中删除它时,对该对象的所有引用都会被删除。需要明确的是:我想确认我的应用程序中不再存在对该对象的引用 我怎样才能做到这一点 到目前为止,我只想到了这个(测试a是否排队): 报告说: 公共静态void gc() 运行垃圾收集器。 调用gc方法意味着Java虚拟机将精力花在回收未使用的对象上,以使它们当前占用的内存可用于

在我的代码中,有许多在运行时创建和删除的对象,它们可能有很长的引用链(也就是说,可以从许多地方进行垃圾收集)

在我的单元测试中,我想验证当我“删除”一个对象时,例如从主要包含它的列表中删除它时,对该对象的所有引用都会被删除。需要明确的是:我想确认我的应用程序中不再存在对该对象的引用

我怎样才能做到这一点

到目前为止,我只想到了这个(测试a是否排队):

报告说:

公共静态void gc()

运行垃圾收集器。 调用gc方法意味着Java虚拟机将精力花在回收未使用的对象上,以使它们当前占用的内存可用于快速重用当控件从方法调用返回时,Java虚拟机已尽最大努力从所有丢弃的对象中回收空间。

(强调矿山)

这是非常模糊的(“尽力而为”),并且似乎是非常不确定的,例如,我必须等待1秒并再次调用
gc()
,或者连续调用它,例如,四次才能将引用排队

有什么方法可以正确地做到这一点吗?我想测试对象是否不会持久存在,并且在正常运行数月后最终会淹没我的内存

备注:

1.)我知道你不应该调用
gc()
,因为这是错误的代码。是的,但是我从测试代码调用它来验证生产代码

2.)我知道,
gc()
从局部的角度来看实际上是不确定的。我意识到这一点,并要求提供更好的替代方案

编辑:


我意识到这可能是一种“特殊”的单元测试:如果对给定的代码库成功一次,我知道这个引用是垃圾收集的;如果单元测试失败,可能是因为
gc()
不想删除它,或者无法删除它。因此,此测试可以验证内存是否已释放,但可能需要多次尝试进行验证。但是,这是“特殊的”(读作:“坏”),因为我必须接受一个随机失败的单元测试。

AFAIK没有办法确保对象已被垃圾收集。调用
System.gc()
通常会导致垃圾收集,但并不总是这样


我还有一个无限运行的Java进程——我在每次迭代开始时调用
System.gc()
,并记录所产生的内存使用量。如果这个数量没有随时间发生显著变化,我可以合理地确定不会“泄漏”内存。

我观察到,当触发堆转储时,它通常会执行完整的GC。如果这是JVM在堆收集期间强制GC的策略,那么您可以通过

kill -3 pid
看看它是否有效

您可能需要添加jvm参数以获取堆转储


我认为使用引用和
System.gc()
进行测试没有问题(尽管我更喜欢弱引用而不是虚引用)。我不记得这种方法有任何稳定性问题

基于引用的方法只有在您能够获得对可能泄漏的对象的引用时才有效

我从NetBeans获得了一个头部转储分析库,我使用它来自动生成某些类型的内存使用情况报告

对于测试代码来说,可以获取堆转储本身,并检查此转储并断言特定数量的给定类型的对象将出现


你可以找到这种方法的例子

使用Java内存分析器会更容易吗?@SteveSmith可能是这样-我必须承认我从未使用过一个。。。然而,我想自动测试一下。一个随机的、危险的、骇人的想法:用一个相对较小的堆启动一个新的VM。在这个VM中,创建您的对象,然后删除所需的对象,然后创建一个infinte链表来使用堆,直到抛出OutOfMemoryError,从而确保执行gc。检查引用是否已清除。如果清除,则测试通过。否则,测试失败。这将是确定性的,但很难创建和维护。我不确定OutOfMemoryError之后VM的行为如何,因此这个想法可能根本不起作用。根据我愚蠢的建议,你可以决定是否付出努力和时间。在测试中,你可以依靠
System.gc
。它不是随机的,它总是工作的,除非关闭。只要没人做,它就不会被关掉。所以,不要这样做,要好好保护自己D@maaartinus谢谢,但我不明白为什么我必须多次调用System.gc()(在两次睡眠之间,或者在我的机器上调用三到四次),才能成功地将该引用排队。我如何知道“正确”的频率?这不是文档中指定的方式(“当gc返回时,它已经尽了最大努力…”),因为如果在连续三次调用后,尽了最大努力成功,那么第一次调用就不是尽了最大努力imho。听起来很有趣。我从未使用过NetBeans堆分析器;您知道不可访问的对象是否仍然存在于“堆上”(即,当它未被垃圾收集时,
heap.getAllInstances()
(在本例中))吗?这取决于具体情况。Heap dump命令可以按原样转储堆,也可以按完整GC和转储。在测试中,我使用第二个选项。虽然API也允许转储未收集的堆,但System.gc()不能保证做任何事情。没有什么可以阻止JVM供应商将其实现为nop。此外,您不能每次都依赖它进行垃圾收集(甚至不知道您将得到的是完整的还是部分的GC),所以永远不要在确定性测试中使用System.GC。
public static class MyClass {
}
kill -3 pid