在我的应用程序的生命周期中,我必须重新创建一个包含其他ArrayList对象的ArrayList(从存储中读取它们)。 ArrayList总是被分配给一个类中的同一个数据成员,实际上是让旧的ArrayList-of-ArrayLists悬空(不可引用或不可访问)。
我的理解是,与C ++不同,这不会导致内存泄漏,因为系统知道对象何时变得不可引用并在其认为合适时释放内存。
但是,旧的习惯很难克服,我几乎本能地通过在重新创建ArrayList-of-ArrayLists之前自己做一些清理来“帮助”系统:
for (InnerArray aList : outerArray)
aList.clear();
outerArray.clear();
我的问题:
答案 0 :(得分:9)
这是多余的。您没有帮助这些对象被释放,因为垃圾收集已经确定它们无法访问。你不能让它们比现在更难以到达。所以,你会浪费一些处理时间来完成任何事情。
但主要的问题是,您会混淆其他开发人员,他们会想知道为什么要清除该阵列。他们可能会浪费时间试图找出你为什么这么做,如果有一些他们最初没有看到的隐藏原因。
C ++开发人员倾向于使用Java代码的类似问题是finalizers;在Java中,你几乎从不想这样做,因为终结器为垃圾收集增加了额外的成本,并且它们不是一种可靠的资源释放方式,因为它们可能不会长时间被调用,或者永远不会被调用。
答案 1 :(得分:3)
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的平台上清除/重用列表可能也有好处。但是,除非我有强有力的证据证明这是一个问题,否则我不会尝试这种“优化”。 (这种优化使您的代码更加复杂,如果操作不正确,可能会导致性能问题。)