If I have a linked list structure, and I implement the clear() method as follows:
public void clear() {
firstNode = null;
size = 0;
}
will it still get correctly garbage collected, or would I want to walk through each node, setting nextNode to null?
None of the nodes can be directly referenced from outside the linked list, so there's no case where there would be a reference to any of them outside my class, but I'm unsure if Java would correctly garbage collect the remaining chained nodes.
That should be fine - Java handles cyclic references etc with no problems.
Since none of the nodes of the list have external references. Setting firstNode to null will make all the nodes eligible for GC as there would be no way to reach any of the nodes from an external reference.
for your information, the LinkedList implementation by Sun parse all elements of the list and set them to null
Related
I have read few posts about garbage collection in Java, but still I cannot decide whether clearing a collection explicitly is considered a good practice or not... and since I could not find a clear answer, I decided to ask it here.
Consider this example:
List<String> list = new LinkedList<>();
// here we use the list, perhaps adding hundreds of items in it...
// ...and now the work is done, the list is not needed anymore
list.clear();
list = null;
From what I saw in implementations of e.g. LinkedList or HashSet, the clear() method basically just loops all the items in the given collection, setting all its elements (in case of LinkedList also references to next and previous elements) to null
If I got it right, setting the list to null just removes one reference from list - considering it was the only reference to it, the garbage collector will eventually take care of it. I just don't know how long would it take until also the list's elements are processed by garbage collector in this case.
So my question is - do the last two lines of the above listed example code actually help the garbage collector to work more efficiently (i.e. to collect the list's elements earlier) or would I just make my application busy with "irrelevant tasks"?
The last two lines do not help.
Once the list variable goes out of scope*, if that's the last reference to the linked list then the list becomes eligible for garbage collection. Setting list to null immediately beforehand adds no value.
Once the list becomes eligible for garbage collection, so to do its elements if the list holds the only references to them. Clearing the list is unnecessary.
For the most part you can trust the garbage collector to do its job and do not need to "help" it.
* Pedantically speaking, it's not scope that controls garbage collection, but reachability. Reachability isn't easy to sum up in one sentence. See this Q&A for an explanation of this distinction.
One common exception to this rule is if you have code that will retain references longer than they're needed. The canonical example of this is with listeners. If you add a listener to some component, and later on that listener is no longer needed, you need to explicitly remove it. If you don't, that listener can inhibit garbage collection of both itself and of the objects it has references to.
Let's say I added a listener to a button like so:
button.addListener(event -> label.setText("clicked!"));
Then later on the label is removed, but the button remains.
window.removeChild(label);
This is a problem because the button has a reference to the listener and the listener has a reference to the label. The label can't be garbage collected even though it's no longer visible on screen.
This is a time to take action and get on the GC's good side. I need to remember the listener when I add it...
Listener listener = event -> label.setText("clicked!");
button.addListener(listener);
...so that I can remove it when I'm done with the label:
window.removeChild(label);
button.removeListener(listener);
It depends on the following factors
how clear() is implemented
the allocation patterns for the entries held by the collection
the garbage collector
whether there might be other things holding onto the collection or subviews of it (does not apply to your example but common in the real world)
For a primitive, non-generational, tracing garbage-collector clearing out references only means extra work for without making things much easier on the GC. But clearing may still help if you cannot guarantee that all references to the collection are nulled out in a timely manner.
For generational GCs and especially G1GC nulling out references inside a collection (or a reference array) may be helpful under some circumstances by reducing cross-region references.
But that only helps if you actually have allocation patterns that create objects in different regions and put them into a collection living in a another region. And it also depends on the clear() implementation nulling out those references, which turns clearing into an O(n) operation when it could often be implemented as a O(1) one.
So for your concrete example the answer would be as follows:
If
your list is long-lived
the lists created on that code-path make up/hold onto a significant fraction of the garbage your application produces
you're using G1 or a similar multi-generational collector
slowly accumulates objects before eventually being released (this usually puts them in different regions, thus creating cross-region references)
you wish to trade CPU-time on clearing for reduced GC workload
the clear() implementation is O(n) instead of O(1), i.e. nulls out all entries. OpenJDK's 1.8 LinkedList does this.
then it may be beneficial to call clear() before releasing the collection itself.
So at best this is a very workload-specific micro-optimization that should only be applied after profiling/monitoring the application under realistic conditions and determining that GC overhead justifies the extra cost of clearing.
For reference, OpenJDK 1.8's LinkedList::clear
/**
* Removes all of the elements from this list.
* The list will be empty after this call returns.
*/
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++;
}
I don't believe the clear() will help in this instance. The GC will remove items once there are no more references to them, so in theory, just setting the list = null will have the same effect.
You cannot control when the GC will be called, so in my view its not worth worry about unless you have specific resource/performance requirements. Personally I'd still with list = null;
If you want to reuse the list variable, then of course clear() is the best option rather than creating a new list object.
In Java an object is either alive (reachable via a reference owned by some other object) or dead (not reachable by a reference owner by any other object). Objects that are only reachable from dead objects are also considered dead and eligible for garbage collection.
If no live object has a reference to your collection, then it is unreachable and eligible for garbage collection. What this also means is that all of your collection's elements (and any other helper objects that it may have created) are also unreachable unless some other live object has a reference to them.
Therefore, the clear method has no effect other than erasing a reference from one dead object to another. They will get garbage collected either way.
How do I delete a linked list completely in java. Some tutorials are suggesting that I should delete it node by node . But if I make head to null simply, would it be wrong ? As all the elements would be eligible for garbage collection.
You can't. You can only recommend the list as a candidate for garbage collection by removing all references to it.
If you own the only reference then setting that reference to null will schedule the object for garbage collection. You can advise a garbage collection using System.gc() but that's not particularly good style and not all JVMs support it.
Removing the elements node by node (use clear()) can help a little since it will reduce the number of references held on each of the list items. That will reduce the amount of memory that the list consumes.
You can point the LinkedList reference variable to null.
Any reference variable referring to null is automatically eligible for Garbage Collection
List list = new LinkedList();
list.add("hi");
list = null; // now eligible for *Garbage Collection*, leave it for JVM to handle
Moreover if you do list.clear() it will clear all the elements inside this list but not the list itself.
Also we can call System.gc() but System.gc() will not ensure that Garbage Collector will run for sure, it can only asks the JVM to run the GC , but is totally dependent on JVM, so we should levae it to JVM only to handle GC.
For more info see this Oracle Doc here
Yes, you can simply assign the head as null but to be on the safe side (as in if some nodes are being referred from elsewhere) it is better to make all nodes null.
If you look at the code in java.util.LinkedList, the clear() method does the same.
/**
* Removes all of the elements from this list.
* The list will be empty after this call returns.
*/
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++;
}
first reference is head in your case.
You can also refer to this comprehensive answer.
Is is possible for me to delete all nodes of my linkedlist to delete by my this code piece? If no then how is it possible to delete all the node at once!
my code is
EditNode mynode=start;
while(mynode!=null){
mynode.editnext=null;
mynode=mynode.editnext;
}
Help needed! Thanks in advance...
Your code dosen't work because you are setting mynode.editnext to null and then trying to reference it. So that's not going to work.
To delete all nodes in a linked list, in Java, just clear the head pointer. Java will garbage collect the rest.
start = null;
Please note that this answer is meant for your custom linked list. In production, you should use the Java implementation of LinkedList, which has a .clear() method on it. This is a much cleaner way to handle a list.
This is because you may have stray pointers which point to an item in the list, and this will keep a reference around to the rest of the list and prevent garbage collection. You shouldn't build organizational structure like the editnext property into the data structure. They should be separate classes.
To clear all of your pointers in each node, use the following code:
EditNode mynode;
while (start != null){
mynode = start.editnext;
start.editnext = null;
start = mynode;
}
Did you check clear() method of LinkedList?
public void clear() - Removes all of the elements from this list. The list will be empty after this call returns.
I have two classes:
Class Node {
int address
}
Class Link{
int latency;
int bandwidth;
Node node1;
Node node2;
}
public Link [] link= new Link[Nmax];
if I want to create a link between two nodes, it is easy, I've just to:
node1=new Node(); //and then I add parameter like address and so on
node2= new Node();//...............
link[1]= new Link();
link[1].node1=node1;
link[1].node2=node2;
link[1].latency=15; //and so on, we suppose that we have 100 nodes and 60 links
Now, during the program, sometimes we add some new nodes then we have to add links between them, I can do this with the same manner us above, my question is:
what I have to do if I want to delete a node ? (links between this node and other existing nodes must be deleted too)
--- Edited in response to jpm's excellent observation ---
In your case, you are doing all of the data structure management yourself, but are not storing enough infomation to undo the additions to the data structure.
You need to store enough information at create time to support the other operations on the data structure. This means that perhaps the choice of an array as your high-level exposed data structure is a bad choice, because there is no guarantee that additions will maintain the sufficient information to support the removals.
Wrap the array in an object, and write the code in the add(...) method to support the efficient removal. This probably means storing more information, which was constructed specifically for the support of removal.
--- Original post follows ---
To delete an object in Java, ensure that nothing "points" to it (has a reference to it) and then wait. Automatic garbage collection will do the deleting for you.
An example to make this clear
link[1] = new Link();
// now we have an extra Link in our array
link[1] = null;
// now garbage collection will delete the recently added Link object.
Note that if you have two or three references to the created Link object, it will not be collected until all the references are lost
link[1] = new Link();
// now we have an extra Link in our array
Link current = link[1];
// now we have two references to the newly created Link
link[1] = null;
// now we have one reference to the newly created Link
current = null;
// now the newly created Link is a candidate for garbage collection
The way this is implemented is there is a top-level Thread of the user implemented program. If that thread can reach the Object in question then it won't get garbage collected. This means that rings and meshes of Objects that are no longer reachable from the live Threads will be collected in mass.
before deleting a node; loop over your links and remove any that have your node to be deleted as node1 or node2, then delete your node.
You probably want to explore using a better data structure than an array for this use case. You want to be able to inspect all Links, figure out which ones refer to the deleted Node, and remove those Links. Start looking at List/Set and see if they suit your needs, and slowly evolve into a good implementation that gives you what you need.
"Deleting" an object in Java means to remove all references that point to the object. The Garbage Collector then eventually will free the memory occupied by the object. So what you need to do, would be to set all references to a specific Node object to null.
// lets delete node1
link[1].node1 = null;
node1 = null;
// at some point the object will be deleted
So I learned that in a singly linked list if you remove a node in the middle, the rest of the list will be garbage collected as well since there will be a ripple effect as each node behind it gets dereferenced.
My question is what about a tree where each node has references to it's children as well as a reference to a parent. If I remove a node in the middle(non-leaf node) would that cause a memory leak since it would reference it's children and they would reference it? So if I wanted to remove a subtree, I would have to remove all the nodes in it from the bottom up?
You should read about the concept of reachability. It is defined in the javadocs, in the description of the package java.lang.ref.
Once an object is not strongly reachable by any thread, it is eligible for garbage collection.
The objects that are strongly reachable by a thread T are:
objects referenced by local variables in the call stack of T,
objects referenced by static fields of any classes, and
objects (strongly) referenced by strongly reachable objects.
If you remove a node from the tree you describe (simply by removing the reference on a parent node to a child), and there are no remaining references to the portion of the tree under the node you removed, then those objects are not strongly reachable. Even if they form some kind of cycle, the JVM is smart enough to determine that those objects are not strongly reachable (that is, they reference each other, but none of them can be reached by any code). Therefore, they are eligible for garbage collection.
You could remove the start node and remove the reference to that node in its parent.
To remove a subtree you just have to remove the reference to it in its parent. So long as no other references are held to it or its children, it will be garbage collected.