1

In Java, having a nested static class Human, I'm wondering if after cleanup of the map variable can make it available for garbage collected. At the moment just before doSomeCode() I called System.gc() and added Thread.sleep(60000) to wait for garbage collector to pick up unreferenced map contents, but no way - it seems map lives in a program unless it is going to finish. My problem is that I need to free up memory because otherwise will get OutOfMemoryError.

What do you think prevents map property of Human class from being recycled? Is it because the Human class is static and thus all its members can not be garbage collected?

import java.util.List; import java.util.ArrayList; import com.carrotsearch.hppc.IntObjectMap; import com.carrotsearch.hppc.IntObjectOpenHashMap; public class TestNestedStaticClass { public static class Human { String name = null; List<Human> children = null; // some data about family members IntObjectMap<int[]> map = null; public Human(String name) { this.name = name; } } public static void main(String[] args) { final List<Human> family = new ArrayList<Human>(); for (int i = 0; i < 1000; i++) { // create and get the family member family.add(new Human("givenName")); Human h = family.get(i); // create map and add some data h.map = new IntObjectOpenHashMap<int[]>(); for (int j = 0; j < 100; j++) { int[] array = new int[1500]; h.map.put(j, array); } } // ... // at some point we want to free the memory occupied by // family.get(i).map for all i from 0 to 1000, so we do: for (int i = 0; i < 1000; i++) { // get the family member Human h = family.get(i); // explicitly remove references from the map for (int j = 0; j < 100; j++) { h.map.remove(j); } // cleanup h.map.clear(); h.map = null; } // ... doSomeCode(); } } 
5
  • 1
    static has nothing to do with why the map is not getting GC'ed. stackoverflow.com/questions/1353309/… Commented Apr 15, 2013 at 17:51
  • I'd half suspect that map just won't get GC'd until that memory is needed for something else. Commented Apr 15, 2013 at 17:52
  • Yes, but I'm having OutOfMemoryError so memory is indeed needed. Commented Apr 15, 2013 at 17:54
  • At which line is the OutOfMemoryError occuring? In doSomeCode() or before? Commented Apr 15, 2013 at 18:07
  • Inside doSomeCode() when I try to create more objects on the Heap. Commented Apr 15, 2013 at 18:08

6 Answers 6

3

From the point where you write: h.map = null;, the map becomes eligible for GC (the removes and clear are technically not necessary).

The reason why you don't see it being GC'ed is possibly due to the fact that you run all that code within the same method, and the GC does not have to collect local variables until the method exits.

If you try to split it in several method it will help the GC (which will get rid of the local variables once the methods exit).

See also this post.

ps: I assumed that you don't have any references to the content of the map or the map itself anywhere else!

Sign up to request clarification or add additional context in comments.

4 Comments

Yes, all that code is inside main, but instead of several methods I did explicit blocking like this { } to make go out of scope when the map is not needed.
@SophieSperner That might not be enough.
I will try to split in several methods, but what if it will not help, this means that garbage collection is not so fast as object creation?
@SophieSperner That is unlikely - if an object can't be created because there is not enough memory, the JVM should try to run the GC first and allocate the new object after. But I would start by making 100% sure that I don't have any references to these objects anywhere (could be a static reference in IntObjectOpenHashMap or one of its parent classes for example).
2

The fact that the Human class is static means nothing - and even if the map variable was static, setting it to null frees up the object content for garbage collection.

If you are running into OutOfMemoryErrors, and you are certain the map contents are the cause, then there must be lingering references to the data somewhere. For example, if I do this:

human.map.put(0, new int[10000]); something.thing = map.get(0); human.map.remove(0); human.map = null; 

Note that a reference to the int[10000] still remains in memory, @something.thing. Cleaning up the map is only part of the work needed to free up the array for garbage collection.

3 Comments

Interesting, I do not see such objects, referring to map contents. But is it possible to check with some profiler? Something that counts object references.
Yes, a good profiler will help you to see what objects are hogging all of the heap in your program. We use JProfiler for such things over here
I would accept your answer as well, but it is allowed to accept only one answer.
0

Note that inner static classes are indeed top classes but just inside a class, so the GC rules to collect their instances are the same rules that GC applies on a common class instance.

Comments

0

There is no need to sleep after System.gc() - the gc method doesn't return until the garbage collector is finished.

An instance of a static inner class is treated the same as an instance of any other class for purposes of garbage collection. You are correctly freeing the map elements of your Human classes (although it's overkill to call map.remove() and map.clear() and map = null - only map = null is needed)

4 Comments

Here 18Rabbit says map.remove() is needed: stackoverflow.com/a/154454/655860
@SophieSperner Once you have written map = null and assuming no other reference to the map ot its content exists, the map and all its content becomes unreachable and therefore eligible for GC.
18Rabbit isn't setting map to null; if he were setting map = null then the remove method wouldn't be necessary.
An ArrayList is an easier example. If you have 100 objects in an ArrayList, and they're not reachable by any other references, then the garbage collector will traverse the ArrayList and mark its elements as "reachable" and so it won't free them. When the ArrayList is unreachable (by setting all of its references to null, or exiting all methods holding its reference, and so on) then its contents are no longer reachable either, and then the GC will be able to free them - there's no need to remove the contents from the ArrayList first.
0

It looks like you are using all primitive data types. This might be a problem, this is just a theory, and I haven't tested it, but it might be worth a try.

Instead of using an array of int's ( int[] ), try using an ArrayList. This should create objects which can be garbage collected, primitive data types are created on the stack not on the heap of objects, therefore they aren't subject to garbage collection?

NOTE: I put a question mark, because I am not positive, someone can confirm or reject my theory.

THEORY REJECTED :( , LEAVING AROUND FOR OTHERS TO READ

4 Comments

Well, I think there is not enough space on the Stack to store int[] objects, so they are probably stored on the Heap.
The only ints the code above is creating are the for loop indexes. @SophieSperner That's not how heap vs stack works.
@Sotirios Not really, int[] array = new int[1500];.
@SophieSperner That's an int[], which is an object. It's stored on the heap.
-3

1) Been a while since I programmed in Java but my guess is the static objects/variables live on in a special place during whole execution of the program.

2) Calling GC explicitly doesn't ensure the objects will be deleted. You simply call the GC and it decides itself (and you cannot really affect this behavior).

1 Comment

yup, the first one was a wild guess

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.