0

In a previous answer on forcing garbage collection, @shams proposes this method from jslibs:

/**
 * This method guarantees that garbage collection is done unlike <code>{@link System#gc()}</code>
 */
public static void gc() {
    Object obj = new Object();
    WeakReference ref = new WeakReference<Object>(obj);
    obj = null;
    while (ref.get() != null) {
        System.gc();
    }
}

but in a comment, @MarkoTopolnik disagree with the fact that this method guarantees that garbage collection is done.

I don't understand why checking if a weak referenced object have been garbaged is not a proof ?

Community
  • 1
  • 1
gontard
  • 28,720
  • 11
  • 94
  • 117
  • 1
    As pointed out in that discussion, at the very least the code should rely on `PhantomReference` instead of `WeakReference`. BTW the method above will either be as good (and as bad) as just `System.gc()`, or much worse: an infinite loop. Some setups explicitly disarm `System.gc()`, see `-XX:+DisableExplicitGC`, for example. – Marko Topolnik Feb 12 '15 at 10:53
  • @MarkoTopolnik - Would *Escape analysis* be able to create obejct obj on the stack itself?. The reference is not escaping and the object is limited to the scope of the method. Don't you think this would be a good candidiate for java 6u23+ JIT optimizations? – TheLostMind Feb 12 '15 at 11:01
  • @TheLostMind When you pass it to the `WeakReference` constructor, it probably escapes. – Marko Topolnik Feb 12 '15 at 11:06
  • @MarkoTopolnik - Ya. The JVM might most probably consider the reference as *escaped*. :) – TheLostMind Feb 12 '15 at 11:10
  • Escape Analysis probably doesn't have anything to do with this as it is a conservative optimization. `System.gc()` is a native call which most likely is treated as unknown behavior by EA and would force the materialization of the object at that point. – the8472 Feb 12 '15 at 13:15

4 Answers4

2

The java command manual entry provides conclusive proof that System.gc() is not guaranteed to cause a garbage collection. In the "Advanced Garbage Collection Options" section, it describes this option:

-XX:+DisableExplicitGC

Enables the option that disables processing of calls to System.gc(). This option is disabled by default, meaning that calls to System.gc() are processed. If processing of calls to System.gc() is disabled, the JVM still performs GC when necessary.

When the javadoc for System.gc() talks about a "best effort", that can mean "no effort at all".


You say:

I don't understand why checking if a weak referenced object have been garbaged is not a proof ?

Your "proof" is based on a fallacy, best illustrated by this:

Today I painted my letterbox and my kitten died.

Can I logically conclude that every time I paint my letterbox, a kitten will die?

Does it also apply if someone else paints a letterbox? Or if I paint my front gate?


And there is another reason why your example may behave differently on different JVMs.

When you assign null to obj, nothing in the remainder of the method's scope reads that variable. The compiler is therefore allowed to optimize away the assignment. As JLS 17.4 says:

"The memory model describes possible behaviors of a program. An implementation is free to produce any code it likes, as long as all resulting executions of a program produce a result that can be predicted by the memory model."

"This provides a great deal of freedom for the implementor to perform a myriad of code transformations, including the reordering of actions and removal of unnecessary synchronization."

If the assignment is optimized away, then the GC could see the previous non-null value in the variable, treat the object is still reachable, and not break the WeakReference.

I cannot tell you if there is a Java implementation that would behave like that, but I would argue that 1) the JLS permits that, and 2) it is a plausible optimization for a JIT compiler to perform.

Community
  • 1
  • 1
Stephen C
  • 698,415
  • 94
  • 811
  • 1,216
  • But by checking if the weak referenced object have been collected, i guess that you are checking than at least an effort have been done. No ? – gontard Feb 12 '15 at 11:09
  • No. 1) You have not proven a **causal link**. 2) Even if I was to accept that there was a causal link, you have only shown this for one run of the application on one particular execution platform with one set of JVM options specified on the command line. All that I need is one example where the application does not terminate and I have a counter-proof by example. – Stephen C Feb 12 '15 at 11:14
  • The Java Memory Model has nothing *at all* to say about local variables. Assignment to a local variable doesn't count as an *action* as defined by the JMM. But this is just one of the many fallacies underlying the claims about the posted idiom. It is at the level of silly-naïve by today's standards and probably dates back to a time when such naïveness was still at large in Javaspace (up to the release of Java 5, for example). – Marko Topolnik Feb 12 '15 at 12:42
  • @MarkoTopolnik - I accept that. But is there anything specific in the JLS that supports my belief that it would be legitimate to optimize away the assignment? – Stephen C Feb 12 '15 at 13:54
  • I actually complemented your observation with an even stronger one: the GC doesn't have to pay any attention at all to local variable assignment. For example, even without the assignment to `null`, the runtime can see that the var is never used again after the constructor call, and behave exactly as if it was assigned `null`. On the other hand, a variable exiting its scope will be technically unreachable, but the runtime may not take notice until the whole method completes. And so on... trying to write foolproof code this way is futile. – Marko Topolnik Feb 12 '15 at 13:59
  • @MarkoTopolnik - agreed. That is my understanding too. But I'm looking for the "language lawyer" justification. – Stephen C Feb 12 '15 at 14:21
  • The language lawyer has precious little to go on with because garbage collection is not covered by the JLS. There's a sentence stating something along the lines of "an object is unreachable if there is no possible future computation which would refer to it"---and the runtime isn't required to take any action at all, anyway. – Marko Topolnik Feb 12 '15 at 14:34
1

As mentioned above, java garbage collection cannot be forced... But it can be helped along. So good java code will always null variables when they are finished, because the act of nulling a variable raises the interest of the garbage collector.

Similarly weak references are more tightly maintained by the garbage collector than other references, that is essentially the purpose of weak references. You have to bear in mind though that weak references are collected if only the defining class itself has a reference to it. That means you cannot use weak references as a substitute for ordinary references.

The art of managing garbage collection is a big subject, and it differs between implementations of Java. Android java is much more aggressively garbage collected than Oracle java for example.

Richard
  • 1,070
  • 9
  • 22
1

I don't understand why checking if a weak referenced object have been garbaged is not a proof ?

In addition to the reasons pointed out by others based on the spec there also is the simple issue that you are trying to test for a full GC. A weak reference may be culled during a young generation collection.

With region-based GCs like G1 partial old-gen GCs are also possible.

And with fully concurrent GCs like Azul's C4 the very notion of "full GC" might not even exist.

And on top of that, even a single full GC pass might not be "complete" in the sense that reference/finalizer queues might be used to lazily dispose of additional objects once some object has been reclaimed, i.e. multiple GC-passes and reference queue processing steps might be necessary depending on program logic to free everything. This can be quite important in the case of native resource disposal based on reference queues.

the8472
  • 40,999
  • 5
  • 70
  • 122
0

As a developer, you can not force the Garbage Collector to run, all you can do, is request it. The JVM will decide whether or not it runs.

There is nothing you can do about that.

Stultuske
  • 9,296
  • 1
  • 25
  • 37
  • But by checking if the weak referenced object have been collected, i guess that you are checking if garbage collection have been done. No ? – gontard Feb 12 '15 at 10:47
  • And how do you check that? By checking the memory freed? Anyway, calling System.gc(); does not guarantee the GC will run. It's merely a request you make, the JVM will decide on itself whether or not to proceed with it, and when. – Stultuske Feb 12 '15 at 10:49