Why can't I just make head=null to delete the complete Linked list?
3 = head > 1 > 2 > 4 > null
By making head = null, JVM will take care of it.As head node is not referenced by any variable , it should be garbage collected.
What is wrong with this solution?
Note: I'm aware of the correct solution to delete the complete link list but I'm curious why I can't just make head=null to delete the complete linked list?
Here's the code of java.util.LinkedList.clear(), verbatim:
public void clear() {
// Clearing all of the links between nodes is "unnecessary", but:
// - helps a generational GC if the discarded nodes inhabit
// more than one generation
// - is sure to free memory even if there is a reachable Iterator
for (Node<E> x = first; x != null; ) {
Node<E> next = x.next;
x.item = null;
x.next = null;
x.prev = null;
x = next;
}
first = last = null;
size = 0;
modCount++;
}
The comment answers your question. It's unnecessary. But it can help the GC, and it can make more objects eligible to GC sooner if there is an Iterator that references one of the nodes: the referenced node still won't be eligible to GC, but all the nodes after and before the referenced node will be, since they're not referenced anymore.
Note that the developer chose to make the clear() method slower (O(n) instead of O(1)), to make the GC faster and reduce "memory leaks". You could do the inverse choice.
Also note that you might never call clear(), and just stop referencing an object of type LinkedList, leaving all the nodes linked together. The GC will collect all the nodes if none of them is reachable through a reference chain from a GC root. That's what happens 99% of the times you use a list.
Related
I want to delete an entire list which I have created in java(note: I am not using internal list in java.util). I have assigned head to null but my question is will the java garbage collector handle the list which has no head or should I delete every node(I mean setting every node to null) which will be handled by java garbage collector? Following is my code, please let me know which one is ok although both works but I would still like to know. Thanks in advance.
//first code
public void deleteList()
{
Node n = head;
Node n1;
head = null;
System.out.println("Deleting list");
while(n != null)
{
n1 = n;
n = n.next;
n1 = null;
}
n1 = n;
n1 = null;
System.out.println("List deleted");
}
//second code
public void deleteList()
{
head = null;
}
It depends on your implementation. If your Node class is internal only (so you don't ever return a Node where it might be saved) and you don't hold any in statics, then there should be no path to any node from a garbage collection root and GC will get rid of them.
So it's probably right, unless your implementation is doing something unusual. (I'm also assuming you don't have a tail variable or anything else that references an internal Node, because those would also need to be set to null).
The Garbage Collector will destroy an object only when the particular object doesn't have any linked internal dependency to other nodes. In other words, whenever the objects are not referenced anymore, they are destroyed and their memory is reclaimed.
your first code is right, when you have internal dependency with other nodes i.e, tail node, for example.
your second is right, when you doesn't have any dependency with other node.
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?
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.
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.
I'm implementing text predictions using a very simple Trie implementation, which is a slightly modified version of this code
It performs better than I initially expected, but I'm receiving an OutOfMemoryError frequently. Any ideas how can solve this problem by either:
increasing the memory designated to my app
optimizing the implementation to use less memory
or any other suggestions?
I've seen recommendations that the memory limitation problems could be avoided by using a native implementation of a part of the code, but I would prefer to stay in Java, if possible.
You could try turning on largeHeap in your manifest to see if it helps:
http://developer.android.com/guide/topics/manifest/application-element.html#largeHeap
By doing this.next = new Node[R]; the implementation allocates an array with 26 pointers to nodes on level 1, then 26^26 pointers to nodes on level 2, then 26^26^26 on level 3 and so on. That could be one reason you run out of memory.
You can try and change the implementation so that every Node has a HashMap of nodes with a small initial capacity, say 5. The HashMap will grow only when there's a real need - which will save some memory.
Another problem in that code is with the delete:
// delete a node
public void delete(Node node) {
for(int i = 0; i < R; i++) {
if(node.next != null) {
delete(node.next[i]);
}
}
node = null; // <-- this is not doing anything!
}
The reason it's not doing anything is that the reference to the node is passed by value in Java - so the real reference remains intact. What you should do instead is:
// delete a node
public void delete(Node node) {
for(int i = 0; i < R; i++) {
if(node.next != null) {
delete(node.next[i]);
node.next[i] = null; // <-- here you nullify the actual array item
} // which makes the object a good candidate for
// the next time GC will run
}
}
So it could also be a memory leak - in case you counted on delete to free space.
I have written a code for deleting all elements of tree.
Need suggestions for following:
In reverseTreeStack method, Can I design without using stack method parameter?
Can I design the entire code in 1 method with better design?
UPDATE : Changed return type of reverseTreeStack to void.Removed additional variable for stack.
public class DeleteTree {
public static void deleteTree(BinaryTreeNode root)
{
Stack stack = new Stack();
reverseTreeStack(stack, root);
while (!stack.isEmpty())
{
BinaryTreeNode node = (BinaryTreeNode)stack.pop();
System.out.println("---------Deleting----------->" + node.getData());
node = null;
}
}
public static void reverseTreeStack(Stack stack,BinaryTreeNode root)
{
if (root != null)
{
stack.push(root);
reverseTreeStack(stack,root.getLeft());
reverseTreeStack(stack, root.getRight());
}
}
}
Why do you need to do this? If I recall correctly, the JVM can free resources once there are no available references to the resource, so just setting your root node to be null should free the whole tree.
I think, James is right, but if you want to practice the tree traversal, or if you want to implement this in a language where you need to free memory manually, then use recursion:
void deleteTree(TreeNode node)
{
if(node==null)return;
deleteTree(node.getLeft());
deleteTree(node.getRight());
System.out.printline("Deleting: "+node.getData())
node = null;
}
Also take a look at Postorder Traversal (thats the only one, that works for deleting)
1) I think you can kill the return value and make it a void method as you are directly manipulating the stack. So just do
Stack stack = new Stack();
reverseTreeStack(stack, root);
// Now just use stack
2) Don't condense things into one method. Breaking things out into more methods will make your code easier to navigate and understand. The less each function is responsible for, the more sense it will make to someone reading it.
Well your reverseTreeStack method can potentially give you a StackOverflowError if your tree is too large, so using a loop instead of recursion there might be a better choice (unless you know for a fact that your trees will never be that large).
Also, why are you "deleting" every node? (node = null actually just removes the reference you have just in that method...) Generally just forgetting the root (root = null) will delete your whole tree if you're structuring it in the classic way of Node(parent, leftChild, rightChild) and not storing pointers to nodes anywhere else.
I need to write my own Deque class and must used a doublylinked list implementation to store data. the problem is writing the method pushfromLeft(Thing thing) which will insert into the left side of the deque. Below is what I have thus far but does not seem to work.
public void pushLeft(Thing thing) {
Node beg = new Node();
Node end = new Node();
Node T = new Node();
if(isEmpty())
{
beg = first;
end = last;
beg = end;
T = beg.thing;
N++;
}
else
{
beg = beg.next;
end = end.next;
T = beg.previous;
N++;
}
Little you do in that method has any effect outside, except changing N and item. Presumably you should be modifying first. It would help if you provide the fields of your class, and what they mean, for context. For instance, it's not clear what item is.
You should also either come up with different conventions for naming member and local variables, or consistently use this., or both.
Might I make a suggestion that may clear a lot of this up for you. it's not what you asked for, but it may be what you need.
Use OO design, this means not operating on something but asking something to operate on itself. What this means is that Node should be more intelligent--currently you are acting on node.
Since Node is doubly linked, it can be pretty smart! It can have methods like:
newNode.insertBefore(currentNode)
newNode.insertAfter(currentNode)
currentNode.remove()
Once you have those, the rest of your code should clean up a bit. They should be trivial to implement given a doubly linked list.
void insertBefore(node existing) {
// first set my stuff up
previous = existing.previous;
next = existing;
// then point other stuff at me
previous.next = this;
existing.previous = this;
}
I think--that's just off the top of my head.
The other question is how do you handle your "Endpoints". Your first and last pointers have to be instances of Node for this to work, but if they are notice that the whole "If" factors out of your original code! Sweet!
Just ALWAYS have a first and last object that start out pointing to each other (and never take on values). When you do your first add, do first.insertAfter() or last.insertBefore() and you are done.
Another possibility, by the way, is to make the list circular--there is no reason that First and Last couldn't be the same "Special" unassigned node, you could still traverse it's Next (which will give you the first real item in the list) and Previous (giving you the last item in your list).
When iterating the entire list, if .value == null, you know you've made it to the other end which makes node.next() and previous() fascinatingly easy to implement (You don't really even need to implement .next, but see below.
/** returns null if there are no more items in the list */
Node next() {
return next;
}
Try it, it will simplify your code a LOT. Most people really don't get how useful actual OO code is.
Also, make all your variables private, it's a good habit to get into. In this case when you are having nodes operate on each other, they can still access each other's private members (not as dirty as it sounds) so you can still have the insertBefore as I wrote it AND you don't have to have getters and setters or public variables. Best of both worlds.
Also notice how your original class that "Operated" on node all but disappears--in fact, it can go away completely. If you needed some specific methods like find(item) or insertSorted(item) there is no reason you couldn't add them to node itself. This may be hard to see until after you implemented it though.
Funny how if you actually code well, most of the complaints people have about Java just don't come up.
Have you looked at the LinkedList source code as a reference?
You definitly don't need to create more than one Node inside adding method. If you want to read from left AND from right later, each Node must remember previous and next element. Then when adding, you just need to re-locate these links, like this:
public void pushLeft(Thing thing) {
Node newNode = new Node();
newNode.setValue(thing); //or just newNode.value = thing;
if(this.isEmpty())
{
this.first = this.last = newNode;
this.n=1;
}
else
{
this.first.previous = newNode;
newNode.next = this.first;
this.first = newNode;
this.n++;
}
}
It vould be wise to create a constuctor for Node class which shoul automaticaly set the value, then you can just wite:
Node newNode = new Node(thing);