【问题标题】:Why Was java.util.Arraylist#clear implemented the way it was in OpenJDK?为什么 java.util.Arraylist#clear 以 OpenJDK 中的方式实现?
【发布时间】:2013-08-16 10:57:53
【问题描述】:

http://grepcode.com/file/repository.grepcode.com/java/root/jdk/openjdk/6-b14/java/util/ArrayList.java#473

public void clear() {
    modCount++;

    // Let gc do its work
    for (int i = 0; i < size; i++)
        elementData[i] = null;

    size = 0;
}

我的问题是,为什么他们必须在支持数组 { O(n) } 中循环以使每个元素都符合垃圾回收条件,而他们本来可以重新初始化支持数组,将整个数组的引用丢弃为整个 { O(1) } 并使其有资格进行垃圾收集? clear() 的 O(n) 性能对我来说似乎不太好,还是我错过了什么?

【问题讨论】:

标签: java performance openjdk


【解决方案1】:

按照他们的做法,您可以重复使用阵列,而无需重新分配其后备存储。如果您想重新分配数组,您可以自己完成,因为ArrayList 的表示主要由其后备存储组成。

如果他们将数组作为一个整体释放,那么调用clear() 和重新分配ArrayList 本身就没有什么区别了。现在,它们为您提供了一个选项,您可以选择是重复使用该阵列还是用一个全新的阵列替换它。

【讨论】:

  • 几乎相同的方式,可以这样做:for (loop_through_list as e) { e = null } //伪代码
  • @SayoOladeji 是的,但这需要一个循环,并且每次将元素设置为null 时都会进行额外的参数检查。当您使用new ArrayList() 时,您是以一行换一行,而不是一行换一个循环。
  • 现在我对看似无辜的def arr = new Object[n]有了完全不同的看法,谢谢!
  • 琐事:在 java 中分配一个新数组时,java 通过将每个值设置为 null 或 0 来自动确保其中没有“垃圾”,除非 JIT 可以检测到整个数组在读取之前写入。将所有值手动设置为 null 将比创建相同大小的新数组提供更高的性能。
【解决方案2】:

此实现允许数组重用而无需重新分配。 Allocating an array in java can be O(n) anyway 因为JVM会将所有元素初始化为默认值。

【讨论】:

    【解决方案3】:

    如果您清除()一个 ArrayList,那么您显然打算重用它 - 因此任何重用都可能包含相同数量的对象。所以避免调整大小操作似乎是个好主意。

    另外,请记住,JIT 编译在这里很重要,可能很多 - 该循环将非常 缓存友好并且各个操作非常便宜 - 可能每个只有一条机器指令在编译的情况下。

    【讨论】:

      【解决方案4】:

      这与clear() impl in Java's LinkedList 的原因相同,即Java Generational Garbage Collection

      这个 ArrayList 和后备数组更有可能被提升到“老一代”,在那里它可以保留由更可能在年轻一代中的数组索引引用的对象。将所有索引设置为 null 允许在收集后备数组之前收集那些较年轻的对象。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2023-04-01
        • 1970-01-01
        • 2018-11-28
        • 2014-04-06
        • 1970-01-01
        • 1970-01-01
        • 2019-09-18
        • 1970-01-01
        相关资源
        最近更新 更多