I’m playing with a horrifying data structure which basically is a tree, and each node stores references to its children in a HashMap object. I’m having troubles freeing memory whenever I need to get rid of the root and all its subtrees except one, by setting this latter subtree as the new root. I thought it might be some bug in my data structure, maybe some reference that I forgot to be there, so nothing becomes eligible for garbage collection. But I wanted to try something much simpler first, and implemented the following test:
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.IOException;
public class MyNode {
MyNode next;
int somedata;
public MyNode(MyNode n) {
next = n;
somedata = 0;
}
public static void main(String[] args) throws IOException {
MyNode p = new MyNode(null);
BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
for (int i=0; i<10000000; i++) {
MyNode n = new MyNode(p);
p = n;
}
while (p!=null) {
MyNode p1 = p.next;
p.next = null;
p = p1;
}
in.readLine();
}
}
When main reaches in.readline(), I can see in htop that the process still has 250MB or so allocated for itself, and nothing gets freed. I obviously first tried to simply do
p = null;
instead of the while loop. But it didn’t work so I came up with the previous code.
Your question is somewhat unclear – are you actually getting OutOfMemoryErrors? What are you trying to solve? There are a few reasons you are seeing the behavior manifested in your test case:
Garbage isn’t collected the moment something is no longer reachable from a GC root – it simply becomes eligible for garbage collection. GC typically is only triggered when there is an allocation failure. Since you aren’t actually allocating anymore memory in your loop that nulls out the references, it is entirely possible the GC just hasn’t run yet.
Even when garbage is collected, the memory in the heap is typically not returned to the OS – so looking at it from the perspective of the OS will not yield an accurate answer. Using VisualVM or tools like jmap and jhat would be the best way to figure out what is actually still on the heap.