CodeWriter
CodeWriter

Reputation: 87

Deallocating memory allocated to objects in Java

In C++ you can deallocate the memory allocated to an object like this:

int main(){
    string myString("MyString");
    string *stringPointer = &myString;
    cout<<myString<<" "<<*stringPointer;
    delete stringPointer;
    cout<<myString; //crash
    return 0;
}

In binary search trees (or any other case), when you need to delete a node, you make it eligible for garbage collection in Java. But you can't do it like this

Node nodeToDelete = getNodeToDelete();
nodeToDelete = null;  //the original reference is still there in the tree

This is like setting a pointer variable to NULL in C++

pointerVariable = NULL;

For the BST delete function to work in Java, we need to go the parent of the node and set the child node to delete to null. Is there a Java language feature like delete in C++ to make things easier?

Upvotes: 0

Views: 1971

Answers (2)

5gon12eder
5gon12eder

Reputation: 25409

No, there is no language feature in Java that allows you to selectively delete a specific object ahead of time (like del in Python). You'll need to trust that the garbage collector will do its job. (And usually, it does so very well.)

Java's garbage collector is based on object reachability (not on reference counting like in CPython, not on memory scanning like in Boehm GC). This mans that any object for which there is no live reference is subject to garbage collection. The reference can be indirect but references from dead objects and dead cycles will not irritate the garage collector.

Some examples:

class Dummy {
    String name;
    Dummy other;
    Dummy(String name) { this.name = name; }
}

void f1() {
    Dummy peter = new Dummy("Peter");
    peter.other = new Dummy("Fred");
    peter.other.other = new Dummy("Megan");
    // None of the objects is eligible for garbage collection since
    // "Peter" is live and "Fred" can be reached via "Peter" (therefore
    // "Fred" is alive) and "Megan" can be reached via "Fred".
    peter.other = null;
    // Now the reference to "Fred" is lost which makes him a candidate
    // for garbage collection.  "Megan" is dead too because the
    // reference from the dead object "Fred" does not count.
    // As the method returns, all three objects are dead and can be
    // collected.
}

void f2() {
    Dummy clementine = new Dummy("Clementine");
    clementine.other = new Dummy("Charles");
    clementine.other.other = new Dummy("Caroline");
    clementine.other.other.other = clementine;
    // Here we have a cycle of
    //
    // +--> "Clementine" --> "Charles" --> "Caroline" --+
    // |                                                |
    // +------------------------------------------------+
    //
    // and since "Clementine" is live, all three are.
    clementine = null;
    // Once we loose the reference to "Clementine", the cycle still
    // exists (every object is referenced by at least one other object)
    // but the cycle is dead.  Hence, all three are subject to garbage
    // collection.
}

The key to using the Java garbage collection effectively is to not keep any references to objects around that you don't need any more. In your binary tree, doing

this.leftChild = null;

will make the entire left sub-tree eligible for garbage collection. (That is, if nobody else is keeping a live reference to one of the nodes.)

Only very rarely you'll want to allow the garbage collector to collect a live object. This can be done using java.lang.ref.SoftReference. The only times I found them useful is for a cache.

import java.lang.ref.SoftReference;

class StoryOfMyLife {
    private final String story;
    private transient SoftReference<String[]> cachedWords;

    public StoryOfMyLife(final String story) {
        this.story = story;
        this.cachedWords = new SoftReference<String[]>(null);
    }

    public synchronized String getWordN(final int n) {
        String[] words = this.cachedWords.get();
        if (words == null) {
            // Called for the first time or cache was garbage collected.
            words = this.story.split("\\s+");
            this.cachedWords = new SoftReference<String[]>(words);
        }
        // Note that we are keeping the cache live for the duration of
        // this method by keeping the reference 'words'.  Once this
        // method returns, the cache becomes subject to garbage
        // collection again.
        return words[n];
    }
}

In this example, the (potentially very expensive) splitting of the long string into words is only done lazily and the result is cached. However, if the system runs low on memory, we allow the cache to be garbage collected since we can re-compute it at any time.

You can read more about the garbage collector built into Oracle's HotSpot JVM at Oracle's website.

Upvotes: 2

Deduplicator
Deduplicator

Reputation: 45654

Java manages memory with reachability-based garbage-collection, thus in order to free memory, just make sure it's no longer reachable.

Few Java-objects need to be cleaned up timely:

Namely those which manage native resources. Use dispose() on them, or if block-scoped, try using.

Side-note: C++ is allergic to freeing memory with the wrong method:

  • Use scope-exit for automatic-storage (that's what you used). This is the basis for RAII.
  • use delete to complement new.
  • use delete [] to complement new[].
  • use free to complement malloc, calloc and realloc.

Upvotes: 0

Related Questions