如何在列表数据结构中编写 clear() 方法?

2022-09-01 19:03:16

我最近阅读了一些框架源代码,并注意到他们编写了类似列表的数据结构的clear()方法。逐个删除元素。

while (_arr.length > 0 )
{

    remove(_arr[0]);

}       

(也许上面的看起来有点令人困惑,但这是因为这种语言本身的本机数组类型是动态数组)或

 for (int i = 0; i < size; i++)
  { elementData[i] = null;}
 size = 0;

但我记得我写过一些这样的代码。该列表装饰了本机数组类型,并且我已经编写了这样的clear()方法。

 _arr=new Array();
 _size=0;

直接实例化新的本机数组类型。

并且此代码是用具有垃圾回收的语言编写的。所以我认为所有元素最终都会被收集,那么为什么需要一个循环呢?新的会很快吗?


答案 1

我猜动机是重用现有的支持数组,而不是分配一个新的支持数组。这一点很重要,尤其是在支持数组非常大的情况下(在极少数情况下,这甚至意味着在垃圾回收旧数组之前无法分配新数组)。

分配新数组(并垃圾回收旧数组)可能比循环访问现有数组并将所有元素的引用设置为 更耗时。null

编辑:如注释中所述,在基于数组的数组中设置引用是不够的。您还必须指示 为空。这是通过将属性设置为 来完成的。nullListListjava.util.ArrayListsize0


答案 2

在某些情况下,清除和重用支持数组会更有效。(显然,您需要一个字段,并且在清除列表时需要将其设置为零!size

  • 清除可减少清空列表时生成的垃圾。
  • 如果以增量方式增长列表(即没有提示),则清除还可以减少重新分配生成的垃圾。capacity

但另一方面,它并不总是一个好主意。例如;clear

  • 如果调用 ,则支持数组的大小与列表已满时的大小相同。如果列表很长,数组可能非常大。而且,如果您再也不需要列表那么长,那么大型数组可能会浪费大量空间。clearArrayList

  • 无论如何,GC 都必须检查 支持数组中的每个单元格,而不管字段的当前值如何。它需要将整个数组复制到“to”空间。ArrayListsize

  • 这也意味着您需要分配给“已清除”的单元格以避免内存泄漏。null

  • 由于代际和/或局部性因素,如果您不断将“新”对象放入大型“旧”数组中,则可能会出现次要性能问题。

简而言之,如果数组支持的列表可能在多个GC周期中幸存下来,那么清除(即清除和重用支持数组的过程)是一个可疑的命题。


推荐