Search code examples
javalinked-listtime-complexityvariable-assignmentspace-complexity

Which is faster, assigning variable directly or saving temp?


So I was reading the source code for java.util.LinkedList and I noticed a design choice that intrigued me. This is pulled from the .clear() method, where they iteratively go through every element in the linked list to remove them all from memory. My question is: why do they define the variable next instead of assigning x directly? Doesn't it take time to copy that element? At the very least, it temporarily takes more space while within that scope.

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

Solution

  • This is actually required. I'll go over the algorithm and code in order to show you why it is needed. Duly note that this question covers topics that are complex, so my answer is slightly formulated to make more sense to a beginner.

    First, it's important to understand what is actually happening internally in the JVM when we use objects. In Java, an object (note not this does not include primitive types), is not actually passed around when we use them. Instead we are using references to objects, which are simply pointers to said objects. We do this so that we can not worry about memory allocation/de-allocation. Now in order to ensure an object is deleted when we no longer needs it, all objects have a count of how many times it is currently referenced within the current state of the program. Broadly speaking, when entering a scope that uses some object, the object's reference count is incremented entering the scope and decremented leaving the scope. Now when an object reaches 0 references, it means there is currently no part of our program that uses this object, therefore it can safely be deleted. This was just a quick summary of how the garbage collection works, but ultimately is more complex.

    This method is iteratively going over each item in the list, and dereferencing each of the items that the current node, x, has a reference too. It is not saying that the objects item, prev, and next should be set to null, only the reference that x has to these objects. This is done so we know that when an object has 0 references, we can safely garbage collect this object. If we were to do as you proposed, such as here:

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

    Then the node x before we assigned it to x.next still maintains the reference to x.next, which is obviously unwanted because that object will continue to float around in memory even if the original x was deleted/goes out of scope.

    To answer your question as to which is faster, it's insignificant. Yes, in that scope we save a few bytes for creating the variable next, but it's important to understand we're only creating a reference to it, we're not actually instantiating a new object, so there is practically no overhead (and optimized for in the JVM). This next object is just allocated temporarily on the stack, of which is overwritten on the next iteration of the loop, so it also does not create any concerns with memory use.