Java集合和垃圾收集器

关于Java Web应用程序性能的一个小问题。

假设我有一个包含10个Rubrique对象的List listRubriques

Rubrique包含一个产品ListList listProducts )和一个客户ListList listClients )。

如果我这样做,内存中究竟会发生什么:

 listRubriques.clear(); listRubriques = null; 

我的观点是,由于listRubriques为空,此列表之前引用的所有对象(包括listProductslistClients )将很快被垃圾收集。 但是因为Java中的Collection有点棘手,因为我的应用程序存在相当大的性能问题,我正在问这个问题:)

编辑:我们现在假设我的Client对象包含List 。 因此,我的对象之间有一个循环引用。 如果我的listRubrique设置为null会发生什么? 这一次,我的观点是我的客户端对象将变得“无法访问”并可能造成内存泄漏?

Java的实际Sun实现不时复制所有引用/生存对象。 然后,复制的空间可以再次用于内存分配。

那说你的例子会损害实际的表现。 listRubriques.clear()是不必要的(除了你在其他地方有一个对它的引用),因为listRubrique引用的所有内容都是垃圾,不再引用listRubriques。 如果变量listRubriques之后超出范围,则listRubriques = null也可能不需要(可能因为它是局部变量,并且方法在此处结束)。

不仅不需要清除调用,因为clear访问后来不再使用的对象的内存,访问对象并且现代处理器将其放入缓存中。 因此,死对象显式转到处理器缓存 – 一些可能更有用的数据将被覆盖以进行该操作。

本文是获取有关Java垃圾收集器的更多信息的一个很好的参考。

编辑 :对问题中的编辑做出反应:垃圾收集器(至少Sun使用的实现)从一些根引用开始,并复制它可以从此引用到达的所有对象以及复制对象引用的对象。 所以你的循环引用对象是垃圾,因为没有’外部’引用指向它们,内存将在垃圾收集中回收。

如果你有:

 listRubriques = null; 

并且没有其他对象持有对listRubriques或其包含对象的引用,它有资格进行垃圾回收。 但是无法保证JVM何时会实际运行垃圾收集并释放内存。 你可以打电话:

 System.gc(); 

向JVM推荐您认为此时运行垃圾收集是一个好主意。 但即便如此,也无法保证。

也有

 listRubriques.clear(); 

在将listRubriques设置为null之前不需要。

编辑 :为了回答有关循环引用的问题,JVM足够聪明,可以确定整个对象图与任何正在运行的代码断开连接,并且JVM将正确地确定它们都符合垃圾回收的条件。 即使在引用计数的旧时代,这一直都是如此。 现代JVM更快,更高效。 但它们不是垃圾收集比旧JVM更多的对象。

“很快”是一个相当模糊的规范,但垃圾收集器可能没有你想象的那么快。 实际收集对象时,很大程度上取决于GC配置和服务器负载,但可能需要一些时间,如果您的VM有足够的可用堆和其他事情要做,那么“很快”就不会收集这些对象。 。

VM规范保证GC将运行的唯一情况是,在某些时候否则将抛出OutOfMemoryError。 在抛出OutOfMemoryError之前,VM有义务尝试至少收集这么多符合条件的对象实例,相关的内存分配请求可以成功(但是仍然不能保证收集所有符合条件的实例)。