Using System.gc

So this is just a habit of mine, whenever a game loop is cancel I usually running a destroy() functions that will clear all List, ArrayList, HashMap, HashSet and so on. Before setting them to null.

A typical destroy function I write looks like this


    public static void destroy(){
 
        System.out.println("Clearing chunks and entities.");
        for(World w : worlds){
            w.entityList.clear();
            w.entityList = null;
            
            w.chunks.clear();
            w.chunks = null;
        }
        
        System.out.println("Clearing worlds.");
        worlds.clear();
        worlds = null;
    }

Then when everything is done I usually run one System.gc just before running System.exit. But I have heard that System.gc should be avoided, and I was wondering is it so bad to run it once before exit the game?

Never try to force GC. Never ever. Never. Nope. Not at all. Not even once.
Whatever you think you are accomplishing, it is not the case.

Why not? I’m not trying to get better performance because of it. I just want to request a garbage collection before closing the game, to clean up.

That’s like brushing your teeth before getting your last tooth pulled.

I think the general reason to avoid forcing GC is because the GC is now optimised enough to be quite efficient on its own, moreso than what you could probably accomplish by forcing it. I.e. It’s best to let it take care of itself.

As for calling it before your game exits, I don’t think it’s worth worrying about. Everything is about to get GC’d in a big apocalyptic way when the JVM shuts down, methinks.

Hehe, java and the OS will clean your app/game up when it is close. That is like asking someone to bust down a door to a building that is about to be blown up to make the blowing up easier. No need.

People sometimes think dead objects are toxic. They aren’t. They’re segments of memory that can be recycled. There is no difference between unreachable “uncollected” objects and “unallocated” space. Garbage collection is a bad metaphor.

Memory is either tagged free or used. Unused (dead) regions are referred to as garbage because there are no object pointers to it that define what the data means; not because it stinks.

Garbage collection is not the process of picking up or moving dead objects. In fact some GC processes are implemented by moving live objects. It makes no sense to “move” dead regions because the slots are “empty” whether they store zeros or ones. Moving meaningless ones and zeros to a new slot just doubles the number of slots filled with meaningless ones and zeros. (Well actually it would only double if the destination did not also store garbage, which would be a bad thing because you never want to interfere with live objects.)

Garbage collection mainly operates in two main ways: 1) Finding live objects and putting a “do not throw away” sticker on it, 2) Finding live objects and moving them to a safe space so they don’t get mashed into bits and melted down to make something new. Garbage collection is a misnomer. The point at which garbage is reused (or “collected”) is actually when new is called. (Note that the GC process makes this more efficient than the C++ allocation process. It comes down to either flipping a bit, removing a linked list node, or incrementing a counter.)

Imagine a post office or storage facility. If you have 1000 boxes and 500 are empty, it doesn’t matter that ten belong to people who haven’t retrieved their stuff in 20 years. If 1000 boxes are full and 200 are unused and you get new customers, you might want to empty the 200 abandoned boxes to make room for them. You would not send someone to patrol with a stop watch to empty single boxes as soon as possible. GC does not work that way either. If you have enough room to serve all your customers there is no reason to expand. Nor would you physically destroy storage space because you may want to use them later and it would be a waste of money both to demolish and rebuild them. (This is kind of how C++ works.) “Garbage collection” (actually scanning, marking, or copying) never needs to be performed if new is never called, so GC is usually delayed as long as possible or until it is scheduled based on what the program (the JRE) thinks is optimal. The JRE will no better than you because it is designed for the platform it runs on and can talk to the OS.

Nulling unreachable references is unnecessary because GC is a process of finding unreachable objects. If something will become unreachable it does not matter what it references because a reference from an unreachable object does not make an otherwise unreachable object reachable.

When the process terminates, all objects never be used again. Therefore there is no need to use GC because GC is only used to find free space.

If you did not know this is how garbage collection works, then you were not equipped to try to “optimize” memory management. The process is more detailed, but these are just the fundamentals. Urban legends about GC, bad metaphors, and outdated thought based on how fairly ignorant C programmers think memory management works are very far removed from reality.

Is this too much Wrong?

 public void disposeAll() {
        batchPlayer.dispose();
        stage.dispose();

        simpleBlackFont.dispose();
        simpleWhiteFont.dispose();
        smallBlackFont.dispose();
        bigFont.dispose();
        verySmallBlackFont.dispose();
        skin.dispose();
        renderer.getMap().dispose();
        renderer.dispose();
        batch.dispose();
        System.gc();
    }

I do that in libgdx…

It depends on what the dispose method does. If it calls native code that tells OpenGL it may release a resource, then the dispose calls may be necessary. It would not be necessary at the end of a program only because the OS would do the same thing.

Forcing GC is kind of similar to condensing a hash table but may be slower and is likely more harmful than good. RAM is not a very scarce resource so shrinking a hash table from 200 elements to 100 elements is just slow and pointless when you have 2.5 extra GB of available. A forced GC operation is likely a waste of time or else it would already have happened. Lots of languages with a function like that replace it with an empty stub in later versions because they get a more sophisticated GC process. System.gc() it may not even do anything in Hotspot, Android, or JS. On the other hand it could make your memory allocation slower or make your memory less compact in multigeneration GC systems (Which is in any environment that has a GC worth using) by pushing young objects into old generations.

If a resource is just a chunk of memory in normal RAM it is completely harmless and will be recycled in a timely manner if it needs to be recycled.

If you think you need to use System.gc(), stop and think again. If you still think you need it, find another solution that usually involves creating less garbage.

If all else fails, and it is completely reasonable to use System.gc(), then you can use it.

Can you think of an example? If you don’t people are left to imagine “completely reasonable” as something along the lines of what their own expectations of GC are.

I can’t give an example, I just know that there is some task out there, however uncommon, that will require you to use System.gc()

I can only think of the collect garbage button I have seen NetBeans, which is a Java IDE with debugger for the Java language, but I have never heard of a use case for it.

I just called System.gc() because im scared of android memory cap :stuck_out_tongue:

It won’t help. Available memory is either there or not. If there is no slot known to be reclaimable then garbage collection gets triggered, at the moment you call new, to find such a space. Space does not need to be free ahead of time. GC is normally done on demand.