哪个更快,直接分配变量或保存临时变量?

时间:2016-12-12 17:56:29

标签: java linked-list time-complexity variable-assignment space-complexity

所以我正在阅读java.util.LinkedList的源代码,我注意到了一个引起我兴趣的设计选择。这是从.clear()方法中提取的,在这里,它们迭代地遍历链表中的每个元素,将它们全部从内存中删除。我的问题是:他们为什么要定义变量而不是直接分配x?复制该元素需要时间吗?至少,它在该范围内暂时占用更多空间。

for (Node<E> x = first; x != null; ) {
    Node<E> next = x.next;
    x.item = null;
    x.next = null;
    x.prev = null;
    x = next;
}

1 个答案:

答案 0 :(得分:0)

这实际上是必需的。我将查看算法和代码,以便向您展示为什么需要它。请注意,这个问题涵盖了复杂的主题,因此我的答案略有表述,以便对初学者更有意义。

首先,了解使用对象时JVM内部实际发生的事情非常重要。在Java中,当我们使用它们时,实际上并没有传递一个对象(注意这不包括基本类型)。相反,我们使用引用来对象,这些对象只是指向所述对象的指针。我们这样做是为了不用担心内存分配/解除分配。现在,为了确保在我们不再需要时删除对象,所有对象都计算当前在程序状态下引用的次数。一般来说,当进入使用某个对象的范围时,对象的引用计数会递增进入范围并递减,从而离开范围。现在当一个对象达到0个引用时,这意味着我们的程序当前没有使用该对象的部分,因此可以安全地删除它。这只是垃圾收集如何工作的快速摘要,但最终更复杂。

此方法迭代地遍历列表中的每个项目,并且解除引用当前节点 x 的每个项目也具有引用。这并不是说对象 item 上一页 next 应该设置为null,只有 x 有这些对象。这样做是因为我们知道当一个对象有0个引用时,我们可以安全地垃圾收集这个对象。如果我们按照您的建议去做,例如:

for (Node<E> x = first; x != null; ) {
    x.item = null;
    x.prev = null;
    x = x.next;
}

然后,我们将节点 x 分配给 x.next 之前仍保留对 x.next 的引用,这显然是不需要的,因为即使原来的 x 被删除/超出范围,该对象仍将继续在内存中浮动。

要回答你关于哪个更快的问题,这个问题是微不足道的。是的,在该范围内,我们为创建变量 next 保存了几个字节,但了解我们仅创建对它的引用非常重要,我们不是实际上实例化一个新对象,因此实际上没有开销(并在JVM中进行了优化)。这个 next 对象只是临时分配在堆栈上,在循环的下一次迭代中会被覆盖,因此它也不会产生任何内存使用问题。