gyorgyabraham
gyorgyabraham

Reputation: 2608

Java: reliably calling GC?

In some library found on google code I came across this util method:

public static void gc(){
    Object obj = new Object();
    WeakReference ref = new WeakReference<Object>(obj);
    obj = null;
    while(ref.get()!=null)
    System.gc();
}

Its doc says it provides a reliable way to call GC, because calling System#gc() is just a hint without any guarantees. I showed it my senior, and he said I should think about why this method is invalid. I read some articles on weak references but I'm still confused. Can somebody show me the point?

Upvotes: 3

Views: 301

Answers (6)

Marko Topolnik
Marko Topolnik

Reputation: 200148

I have direct experience with the supposed "safe GC" idiom you have posted.

It doesn't work.

The reason is quite simple: just the fact that a weak ref is cleared is not a signal that the object has been collected; it only means that it has become unreachable through any strong or soft reference. In my experience this signal arrives before the object is reclaimed.

A better attempt would be to use a Phantom reference, which at least ensures that the object has entered the finalizable state, but once again, it can still be occupying the heap, and in practice it still is occupying it. Another explanation could be that this particular object, obviously residing in Eden space, did get reclaimed, but the GC run which did it was not exhaustive and there is more memory to reclaim in other generations.

On the other hand, I have very reliably used this trivial idiom:

for (int i = 0; i < 3; i++) { System.gc(); Thread.sleep(500); }

Try it and see if it works for you. The sleep part is optional: it is needed only if System.gc() uses concurrent sweeping.

If you object to the apparent fickleness of this approach, just remember that any approach to explicit GC-ing is fickle. This one is at least honest about it—and just happens to work on actual systems. It is, naturally, non-portable and can cease to work at any time for a large array of reasons. Even so, it is the best you'll ever get.

Upvotes: 7

Aaron Digulla
Aaron Digulla

Reputation: 328556

Code that tries to force GC is usually a sign for an underlying bigger problem (i.e. design issue or missing knowledge on the developers part).

I have seen a few use cases where calling System.gc() in production code actually makes sense, for example, before printing the current memory usage - it doesn't matter if the values are off but we'd like to improve chances the values are as small as possible. Of course, we knew that GC was enabled - we used this to automatically detect memory leaks on a QA system.

In general, calling System.gc() yells "my code is buggy and I don't know how to fix it!".

Upvotes: 0

bNd
bNd

Reputation: 7630

Programmatic we need to ensure that, when a obj is removed then its corresponding entry should be removed. Only then, that object becomes a candidate for garbage collection. Otherwise, even though it is not used at run-time, this stale object will not be garbage collected.

The object to which this reference refers, or null if this reference object has been cleared. As your object reference of WeakReference class. so it will not give null. but after removing gc., it provide null.

 Object obj = new Object();
         WeakReference ref = new WeakReference<Object>(obj);
         obj = null;
         if(ref.get()!=null)
         {
             System.gc();
             System.out.println("remove ref");
         }
         if(ref.get()!=null){
             System.out.println("not execute"); 
         }

Output:

remove ref

Don't assign null value to obj.

 Object obj = new Object();
         WeakReference ref = new WeakReference<Object>(obj);
         if(ref.get()!=null)
         {
             System.gc();
             System.out.println("remove ref");
         }
         if(ref.get()!=null){
             System.out.println("execute"); 
         }

Output:

remove ref
execute

Upvotes: 0

blgt
blgt

Reputation: 8205

The point is that your thread will stop and wait until the weak reference is cleared, thus "simulating" garbage collection. There's no guarantee when (or indeed even IF) this will actually happen.

You could be stuck waiting on this while for a long, long time.

Upvotes: 0

Voo
Voo

Reputation: 30216

There is no way to guarantee a GC call because just as the documentation says System.gc is just a hint that can be ignored by the system.

So assume that the JVM ignores System.gc - in that case the whole thing just loops until some other part of the systems causes a GC. If you run single-threaded or nobody else allocates much memory you basically create an inifite loop here.

Upvotes: 1

Joop Eggen
Joop Eggen

Reputation: 109547

The point is, that System.gc() does not need to clean up all weak references. And consider some Java virtual machines too. If System.gc for once (the first time) does decide to not clean that reference, it is very likely to the next call. Hence you have a possibly infinite loop. Probably depending on other threads changing the state for the garbage collection to terminate the loop.

So: once is enough.

Upvotes: 2

Related Questions