这种形式的内存管理在Java中是否有意义?

时间:2011-09-01 02:59:21

标签: java memory-management memory-leaks garbage-collection

在我的应用程序的生命周期中,我必须重新创建一个包含其他ArrayList对象的ArrayList(从存储中读取它们)。 ArrayList总是被分配给一个类中的同一个数据成员,实际上是让旧的ArrayList-of-ArrayLists悬空(不可引用或不可访问)。

我的理解是,与C ++不同,这不会导致内存泄漏,因为系统知道对象何时变得不可引用并在其认为合适时释放内存。

但是,旧的习惯很难克服,我几乎本能地通过在重新创建ArrayList-of-ArrayLists之前自己做一些清理来“帮助”系统:

for (InnerArray aList : outerArray)
  aList.clear();
outerArray.clear();

我的问题:

  1. 这是多余的吗?
  2. 我弊大于利吗?
  3. 这有什么好处吗?
  4. 为什么?

3 个答案:

答案 0 :(得分:9)

这是多余的。您没有帮助这些对象被释放,因为垃圾收集已经确定它们无法访问。你不能让它们比现在更难以到达。所以,你会浪费一些处理时间来完成任何事情。

但主要的问题是,您会混淆其他开发人员,他们会想知道为什么要清除该阵列。他们可能会浪费时间试图找出你为什么这么做,如果有一些他们最初没有看到的隐藏原因。

C ++开发人员倾向于使用Java代码的类似问题是finalizers;在Java中,你几乎从不想这样做,因为终结器为垃圾收集增加了额外的成本,并且它们不是一种可靠的资源释放方式,因为它们可能不会长时间被调用,或者永远不会被调用。

答案 1 :(得分:3)

  1. 是 - 老实说,我只是不明白。如果你不再需要一个物品,只要确保你不能再访问它了,那就太好了!
  2. 是 - 调用可能会使用处理能力,垃圾收集可能会少用掉掉一个对象。 Nate建议,这也可能令人困惑。
  3. nope - 我没有看到任何好事,抱歉。
  4. 见上文,欢迎来到Java!你现在可以专注于有趣的东西:)
  5. P.S。我不确定我现在要说什么,但clear()函数可能会删除ArrayList中的元素,只需确保您无法通过ArrayList访问它们变量。可能它不会“破坏”它们,但它只会使它们有资格进行垃圾收集。很高兴知道该功能是如何实现的......

    P.P.S。您可能想要自己调用GC,不要这样做!请参阅related question

    修改

    以下是来自clear()的{​​{1}}:

    ArrayList

答案 2 :(得分:3)

  

1)这是多余的吗?

  

2)我弊大于利吗?

  

3)这有什么好处吗?

没有

  

4)为什么?

clear()上调用ArrayList会更改列表的size字段,然后小心地将null分配给其后备阵列中刚刚变为无效的元素。 clear()的代码需要这样做,因为这些元素中的引用可能导致其他对象保持可访问状态;即泄密记忆。

但是,当ArrayList无法访问时,垃圾收集器将不再再次查看支持数组的任何元素。 GC的标记过程仅遍历可到达的对象,并且回收过程不会查看垃圾对象/数组的内容。

因此,基本上,在一个即将无法访问的对象上调用clear()会浪费CPU周期和内存/ VM带宽。 (当然,这是多余的代码,下一个人将要抓挠他的头......)


事实上,调用clear然后重复使用列表是一个好主意甚至是值得商榷的:

  • 调用clear不会释放/调整后备阵列的大小,因此您可以留下一个巨大的后备阵列,用于列表,其大小通常很小。

  • 垃圾收集器可以释放足够大的阵列并分配一个比clear()更快 的新阵列,这是不可想象的。 (首先,GC可以使用多个处理器,其中clear()的调用将在一个线程上运行。)

  

是否存在实际上有理由调用clear()的方案?

清除/重用列表绝对必要的唯一情况是,当其他内容引用特定的列表并且您无法更新列表引用时。

在具有受限内存和/或慢速GC的平台上清除/重用列表可能也有好处。但是,除非我有强有力的证据证明这是一个问题,否则我不会尝试这种“优化”。 (这种优化使您的代码更加复杂,如果操作不正确,可能会导致性能问题。)