Java集合和垃圾收集器

时间:2010-01-18 14:48:00

标签: java performance collections garbage-collection

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

假设我有一个List<Rubrique> listRubriques,其中包含十个Rubrique个对象。

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

如果我这样做,记忆中会发生什么:

listRubriques.clear(); listRubriques = null;

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

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

3 个答案:

答案 0 :(得分:15)

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

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

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

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

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

答案 1 :(得分:3)

如果你有:

listRubriques = null;

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

System.gc();

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

还有

listRubriques.clear();

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

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

答案 2 :(得分:1)

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

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