javamemory-leaksgarbage-collectionset

Java cleared collection not freeing up heap


I am currently developing a game and choose Java as my main development platform. I kind of regret this now since I have encountered a major memory leak which I do not fully understand. I am by far not new to Java, but for some reason, I just can't wrap my head around this error. The basic problem is that I load my gameworld in pieces in order not to use too much memory. After the player leaves an area, set area which is saved within a map, gets removed from the map. For some reason, the garbage collector does not delete the area after that and the amount of ram spend just keeps increasing until I stop the game. From my understanding of the garbage collector, it should delete heap variables when there is no thread accessing the object any longer which is the case in my game.

Because my game engine is already pretty big and too complex to experiment with, I made a small test program to check whether my understanding of the garbage collector is "garbage ;P" or not. (I know I am punny, right?... sry ^^)

Here is the program:

public static void main(String... args) throws InterruptedException {

new Thread(() -> {
    try {
        Set<Long> set = new HashSet<>();

        System.out.println("Saving stuff");
        for (long i = 0; i < 19999999L; i++) {
            set.add(i);
        }

        Thread.sleep(10000);

        System.out.println("Clearing stuff");
        set.clear();
    } catch (InterruptedException e) {
        e.printStackTrace();
    }
}).start();

    Thread.sleep(40000);
    System.out.println("Exiting program!");
}

As you can see, I am basicaly just saving a bunch of longs in a HashSet and clearing it afterwards. To make sure, that the longs would not be accessed any longer, the thread which they belong to even stops. But for some ood reason no memory frees up.

During my carrer as a programmer I have never been this confused about an issue like I am right now. I hope I can resolv this without rewriting everything in C++, which would realy suck since the program has gotten insainly big over the months I have worked on it so far.

I am happy for any help you guys can provide and I realy hope I can solve this one, Thank you in advance :)


Solution

  • Do not expect a Java application to release memory back to the OS following a garbage collection.

    The normal behavior of a JVM is to keep the heap size large so that it doesn't need to run the GC often. It is "eager" to request more memory from the OS, and "reluctant" to give it back.

    (But if the JVM does decide that the heap is too big, it will give some memory back. Eventually. You typically need at least 2 full GC cycles before this happens, and the behavior depends on the GC used, other GC option settings, JVM versions, etc.)

    But here's the thing. If you did the same thing in C++, there is a good chance that the normal C++ allocator would not give back memory to the OS either. Certainly it wouldn't be able to do that if the creation and destruction of the big data structure resulted in fragmentation of the C++ heap.