0

General question

In Java, there is no reference pointing to an object, but one of the methods of this object is still on the call stack.
Is it possible that the garbage collector removes this object before its method is popped off the call stack, or does it wait until the method is popped off?
(please refer to my specific problem below)

Specific problem

Class structure

Implementation of a simple singly linked list:

  • class LIST: attribute "begin" of type LIST_ELEMENT
  • abstract class LIST_ELEMENT with all needed abstract methods
  • the classes END and NODE inherit from LIST_ELEMENT
  • END does not have any attributes, it always marks the end of the list
  • the attributes of NODE are "next" of type LIST_ELEMENT and "data" of type DATA_ELEMENT
  • DATA_ELEMENT is an interface which has to be implemented by any class that is to be stored in the list

Methods of LIST

  • insertSorted: inserts an element while keeping a sorted list sorted
  • sort: sorts the list by first clearing the list and then by using the method insertSorted to insert each element again

Code

public class LIST
{
    private LIST_ELEMENT begin = new END();

    // some methods to add or remove elements

    public void clear()
    {
        begin = new END();
    }

    public void insertSorted(DATA_ELEMENT dataNew)
    {
        begin = begin.insertSorted(dataNew);
    }

    public void sort()
    {
        begin.sort(this);
    }
}
public abstract class LIST_ELEMENT
{
    public abstract LIST_ELEMENT insertSorted(DATA_ELEMENT dataNew);
    public abstract void sort(LIST list);
}
public class END extends LIST_ELEMENT
{
    @Override
    public LIST_ELEMENT insertSorted(DATA_ELEMENT dataNew)
    {
        return new NODE(this, dataNew);
    }

    @Override
    public void sort(LIST list)
    {
        list.clear();
    }
}
public class NODE extends LIST_ELEMENT
{
    private LIST_ELEMENT next;
    private DATA_ELEMENT data;

    public NODE(LIST_ELEMENT nextNew, DATA_ELEMENT dataNew)
    {
        next = nextNew;
        data = dataNew;
    }

    @Override
    public LIST_ELEMENT insertSorted(DATA_ELEMENT dataNew)
    {
        if(data.isSmallerThan(dataNew))
        {
            next = next.insertSorted(dataNew);
            return this;
        }
        else
        {
            return new NODE(this, dataNew);
        }
    }

    @Override
    public void sort(LIST list)
    {
        next.sort(list);
        list.insertSorted(data);
    }
}
public interface DATA_ELEMENT
{
    public boolean isSmallerThan(DATA_ELEMENT dataCompare);
}

Question

Having implemented this sorting algorithm, is it safe?
Can the garbage collector remove the data from the NODE objects after the list was cleared (so the call list.insertSorted(data); does something unexpected), or does the method on the call stack count as a reference to the object so that the data attribute is valid for the entire duration of the call of LIST.sort? Is it guaranteed that the object is not removed during this time?

In my testing, the call to LIST.sort always sorted the list as expected.

RedError
  • 28
  • 4

2 Answers2

3

It seems, you have a fundamentally wrong understanding of what a garbage collector does. You wrote

Can the garbage collector remove the data from the NODE objects after the list was cleared (so the call list.insertSorted(data); does something unexpected), or does the method on the call stack count as a reference to the object so that the data attribute is valid for the entire duration of the call of LIST.sort? Is it guaranteed that the object is not removed during this time?

A garbage collector will never remove something. A removal is an action in your application logic, like changing the next fields of your node objects. A garbage collector will never perform such actions.

Likewise, the semantics of your “list” do not affect the garbage collector. To the garbage collector, an instance of your LIST class is just an object with a reference to another object. When the garbage collector decides to reuse the memory of the LIST instance, it does not affect the LIST_ELEMENT you might be still working on. It does not collect “the entire list”, as to the garbage collector, there is no such thing as a list.

As a simple rule of thumb, unless you write code with a special interaction with the garbage collector, like a finalizer or cleaner, or are dealing with the special weak, soft, or phantom reference objects, you will never notice the garbage collector’s activity. It will reuse the memory of those objects whose memory is not needed by the application, in other words whenever your application won’t notice it.

That said, contrary to the other answers, executing an instance method does not prevent the garbage collection of an object that is otherwise unused. But how could it be otherwise unused? That would imply that even the caller has no other reference to the list (or won’t use it). So who cares about the contents of the list, if no reference to the list exist? The other scenario would be that the JVM has optimized the code such that it doesn’t need the memory of the object, e.g. because it keeps all field values in CPU registers. You would again not notice anything, as the behavior of the program remains the same.

A real-life example has been documented in finalize() called on strongly reachable objects in Java 8 where an object truly got finalized while a method invocation on the object was ongoing. But as said, such things can only have a perceivable effect on the application’s behavior when you interact with the garbage collector explicitly. In the linked Q&A, it was a finalizer producing a noticeable effect.

Holger
  • 285,553
  • 42
  • 434
  • 765
1

In Java, there is no reference pointing to an object, but one of the methods of this object is still on the call stack.

This cannot happen. If a method is running, there is a reference to an object whose method was called.

Is it possible that the garbage collector removes this object before its method is popped off the call stack, or does it wait until the method is popped off?

As long as method is running, there is a reference to the object. That's why such object cannot be removed.

mentallurg
  • 4,967
  • 5
  • 28
  • 36
  • 1
    The reference to the object is what `this` refers to. – Stephen C Jun 14 '20 at 12:44
  • @StephenC: Within teh class code - sure. But there are also reference to other objects. I don't understand if you don't agree with anything or if you don't understand anything. – mentallurg Jun 14 '20 at 12:45
  • 1
    Well ... given that I have a gold badge for Java, I probably don't understand anything at all about Java :-). (Hint: I am making a suggestion to improve your answer.) – Stephen C Jun 14 '20 at 12:49
  • 1
    @StephenC: Who knows? :) Your very first comment does not add anything what is missing, it does not change anything, it does not point to any wrong statement. Can you explain the purpose of your first comment? – mentallurg Jun 14 '20 at 12:52
  • @StephenC: To "this" - it is obvious that it is a reference. Besides, the OP does not ask anything particular about "this". One should considers the whole call stack. – mentallurg Jun 14 '20 at 12:57
  • 2
    Do you know [this Q&A](https://stackoverflow.com/q/26642153/2711488) or [this bug report](https://bugs.openjdk.java.net/browse/JDK-8145304)? “This cannot happen” is a strong wording for something that did already happen. We could close this question as a duplicate of [Can java finalize an object when it is still in scope?](https://stackoverflow.com/q/24376768/2711488), if there wasn’t the OP’s wrong assumption that the garbage collection activity could affect the validity of an algorithm that needs to be addressed. – Holger Jun 15 '20 at 10:01