linked list deletion in java - java

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.

Related

Java: efficiently (and safely) remove sequence of elements in a final SortedMap<K,V>?

I'm trying to trace a memory leak in Java. Does this snippet actually prevent the garbage collection.
SortedMap<K,V> cache = ... /* some sorted map */
// and later in a loop, I do
cache = cache.tailMap(someIndex); // does this prevent gc of elements < someIndex
The elements < someIndex are not available anymore in follow-up code. Are they also garbage collected? I'm running into a java.lang.OutOfMemoryError after a while, not sure if this is the reason...
I cannot create a temporary map and reassign like
tmp = new SortedMap<K,V>();
tmp.putAll(cache.tailMap(someIndex));
cache.clear();
cache = tmp; // this breaks the "final"
as I need the original cache object, because it's final. How do I schedule those elements < someIndex for GC, i.e. do I really need to call remove() in a loop? Is there a better way than this?
// "TreeSet" to make sure the keys are ordered
Iterator<K> it = new TreeSet<K>(cache.keySet()).iterator();
while (it.hasNext())
{
if (it.next() < someIndex) it.remove();
else break;
}
Edit: SOLVED
Actually the above was not working as expected. Of couse, it was necessary to remove the elements in the map, not within the keyset!
// "TreeSet" to make sure the keys are ordered
Iterator<K> it = new TreeSet<K>(cache.keySet()).iterator();
while (it.hasNext())
{
K key = it.next();
if (key < someIndex) cache.remove(key); // not it.remove();
else break;
}
Edit 2
Most elegant, as suggested by Louis Wassermann below, this is what I was originally after:
cache.headMap(someIndex).clear();
No iterator, no key set, no need to loop - beautiful! Thank you!
Javadoc (https://docs.oracle.com/javase/7/docs/api/java/util/SortedMap.html#tailMap(K)) is quite clear : the tailMap() method return a view of the map, backed by the original map. Elements are not removed from the original map, and the original map is still reachable as the new map has a reference on it.
In your case, you must call remove to effectively make objets garbageable.
If cache is reachable from a GC root, then the map and its keys will not be eligible for garbage collection. What you looking for is a key eviction policy or data-structure.
Guava Cache might be a good option.
Yes, tailMap() creates a view that retains a reference to the parent object. You need to clean up that parent object.
SortedMap<K,V> cache = ... /* some sorted map */
// and later in a loop, DO THIS INSTEAD:
cache.headMap(someIndex, false).clear();
This change through the headMap() view removes unnecessary entries from the underlying cache map.

Garbage collector vs. collections

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 to delete objects?

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

Delete/free a linked list node in Java. Suggestion please

All,
If I were to write a function to delete a node (given headNode and data as input parameters) from a linkedList in Java. I would find the node that has "node.data=data", and delete it by pointing its previous node to its next node *^. My question is, do we have to point the "to be deleted" node to null? to free the memory? or the GC will take care of objects no more accessed in heap.
*^: say A->B->C->D , if B.data=data, then make A->C . is B->Null necessary?
please let me know if its not clear, I will edit it. Thanks.
If you want to delete Node B you just need for A to point to C. The garbage collector will take care of your B nodes as there won't be any references left to it.
The following explanation is quoted from http://javarevisited.blogspot.com/2011/04/garbage-collection-in-java.html
An Object becomes eligible for Garbage collection or GC if its not reachable from any live threads or any static refrences in other words you can say that an object becomes eligible for garbage collection if its all references are null. Cyclic dependencies are not counted as reference so if Object A has reference of object B and object B has reference of Object A and they don't have any other live reference then both Objects A and B will be eligible for Garbage collection.
Generally an object becomes eligible for garbage collection in Java on following cases:
1) All references of that object explicitly set to null e.g. object = null
2) Object is created inside a block and reference goes out scope once control exit that block.
3) Parent object set to null, if an object holds reference of another object and when you set container object's reference null, child or contained object automatically becomes eligible for garbage collection.
4) If an object has only live references via WeakHashMap it will be eligible for garbage collection.
As everyone has said you don't need to set it to null. I just want to add that I had a similar question before which might not be obvious. If you have a doubly linked list, where each node references the previous and the next node, for example A-B-C-D and you remove C-D so that you're left with A-B. You also do not need to worry about C or D even though both of them still have a reference to them (from the other one). Apparently the GC is smart enough to take care of that case as well
No you don't have to set B to null. The Java garbage collector will free the memory for any object not reachable anymore.

Linked List Implementation In Java and Garbage Collection

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

Categories