2010-01-18 129 views
12

一个小问题关于一个Java web应用程序的性能。Java集合和垃圾收集

我们假设我有一个List<Rubrique>listRubriques十个Rubrique对象。

一个Rubrique包含的产品之一名单(List<product>listProducts)和客户端的一个列表(List<Client>listClients)。

如果我这样做到底发生了内存:

listRubriques.clear(); listRubriques = null; 

我的观点是,由于listRubriques是空的,我以前这个列表中引用的所有对象(包括listProductslistClients)会垃圾收集很快。但由于收集的Java是有点棘手,因为我有我的应用我要问的问题:)

编辑相当的性能问题:现在让我们假设,我的客户对象包含List<Client>。因此,我在我的对象之间有一种循环引用。如果我的listRubrique设置为null,那么会发生什么?这一次,我的观点是,我的客户对象将变成“无法访问”和可能创建一个内存泄漏?

回答

14

实际的太阳执行的Java副本不时所有引用/生命物体。然后可以将复制的空间再次用于内存分配。

这就是说你的例子实际上损害表现。 listRubriques.clear()是不需要的(除非你持有别的引用),因为listRubrique引用的所有东西都是垃圾,所以listRubriques不再被引用。如果变量listRubriques事后超出范围(可能是因为它是局部变量并且方法在此处结束),那么listRubriques = null也可能不需要。

不仅调用明确的是不必要的,因为明确的访问那是以后不再使用,对象访问和现代的处理器将会把它放入自己的高速缓存中的对象的内存。因此,一个死对象明确地进入处理器缓存 - 一些可能更有用的数据将被覆盖该操作。

This article是一个很好的参考,以获取有关Java垃圾收集更多的信息。

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

+0

小心:你的第一句话描述了当前实施了Sun JVM的。这通常不是关于Java的说法。尽管答案的其余部分似乎一般适用。 – 2010-03-08 15:05:43

+0

感谢您的提示,我改变了第一句话。 – Mnementh 2010-03-08 15:16:25

3

如果您有:

listRubriques = null; 

没有持有引用listRubriques其他对象或其包含的对象,它的资格进行垃圾回收。但是不能保证JVM什么时候会真正运行垃圾收集和空闲内存。您可以拨打:

System.gc(); 

建议,你认为在这个时候运行垃圾收集是一个好主意的JVM。但即使如此,也没有保证。

而且具有

listRubriques.clear(); 

设置listRubriquesnull之前是没有必要的。

编辑:要获得关于循环引用问题,JVM中有足够的智慧弄清楚整个对象图是从任何正在运行的代码断开,JVM会正确地确定,他们都是符合垃圾回收。即使在参考计数的古老时代,这一直是真实的。现代JVM更快更高效。但它们并不是垃圾收集比旧的JVM更多的对象。

+0

关于在null之前清除,我只是为了确保我的对象不再有任何引用。但我确定这是一个无用的双重检查。 我读了System.gc();在老版本的java中很有用,但现在完全被忽略了,不是吗? – Anth0 2010-01-18 15:01:15

+0

@ Anth0:我没有听说和Java 6的J2SE文档中没有提过类似的事情(http://java.sun.com/javase/6/docs/api/java/lang/System.html #GC() )。为了获得最大的可移植性,最好不要对您的应用程序将运行的JVM实现做任何假设。看看这篇文章从太阳有关垃圾回收的真相:http://java.sun.com/docs/books/performance/1st_edition/html/JPAppGC.fm.html – Asaph 2010-01-18 15:07:40

+0

调用System.gc()的通常是由新颁发虚拟机,尽管不能保证。如果您要求GC运行,虽然没有必要,但您可能会造成性能问题,而不是解决性能问题。 – jarnbjo 2010-01-18 15:12:55

1

“很快”是一个相当模糊的规范,但垃圾收集可能是不一样敏捷,你似乎期望。实际收集的对象很大程度上取决于GC配置和服务器负载,但可能需要一些时间,并且如果您的虚拟机有足够的可用堆和其他事情,则不会很快收集这些对象, 。

其中VM规范保证了GC将运行的唯一情况,就是当在某一点,否则一个OutOfMemoryError会被抛出。引发OutOfMemoryError之前,VM有义务作出尝试至少收集这么多的符合条件的对象实例,将相关的内存分配请求都能成功(但你还是不能保证所有资格实例收集)。