Is there a way to FORCE weak and/or soft referenced objects to be GC'd in Java?
Asked Answered
A

1

12

Here's my use case. We are trying to narrow down a potential memory leak in an application, and we are using a memory analysis tool to snapshot the heap so we can look for object instances and references. (In case it helps, we're using YourKit.)

This application makes extensive use of dynamic and CGLIB proxies, which end up storing tons of references to classes and classloaders in WeakHashMaps.

After our test case runs, we are expecting all hard references to object X and its classloader to be gone, but since there were many proxies involved in the test case in the end we have many weak/soft references left to it. (I can only find WeakHashMap references, but YourKit wraps both weak and soft references into one line item in the summary so I can't be sure I'm not missing a soft reference somewhere.)

This is true even after requesting a full GC from the JVM. (Using the sun 1.6.0_23 JDK in server mode.)

It seems as though the JVM admits there are only weak/soft references to these objects, but I can't get force it to GC these things to be 100% sure. (So, what I want is for this to disappear entirely from the heap and its classloader usage of permgen to also go away.)

Anyone know of a way to configure and/or force the JVM to dispose of objects only soft/weakly referenced?

Aldric answered 6/8, 2011 at 16:25 Comment(4)
Did you register your objects to global events by any chance? Perhaps a static field (or another thread object or something else) has a reference to them...Krefeld
Good question - had already looked into this and YourKit provides enough information to find these kinds of things quickly. While I am still investigating, so far I've narrowed this down (I think) to some behavior initiated by Spring's AOP when it proxies classes/methods using the RegexpMethodPointcutAdvisor. HOWEVER, it is only one special case (so far) of this advisor - we use this in numerous places that does NOT seem to create this problem. Still working on identifying what is unique about the one case that does... will post back when I have more.Aldric
Ok, so here's the update. I believe I've found the smoking gun for my particular issue. One of the proxies used in our application lazily-loads its implementation when needed from a cache to ensure that the operation always happens on the most recently cached object. If the cache doesn't have the object, the cache has been configured to instantiate and initialize the object. The proxy is a rather dumb proxy that for any method invocation, it asks the cache for the object, then invokes the method on the object. Comments have a char limit, so read on...Aldric
...SO, in some cases the object is NOT already cached, but the proxy is in existence. When the proxy gets finalized, therefore, it will load the object in question and store it in the cache. While I've not traced through all the paths of dependency, somehow this results in the garbage collector deciding NOT to collect these weak references, which then cascades into all weak references to the classloader not being collected. This implies that it created a strong reference to the classloader in question, but if so, the tools I'm using (YourKit and jmap/jhat) don't show that to me.Aldric
O
11

Calling GC should always release all weakly-reachable objects (assuming the "request" made by calling System.gc is actually granted). If weak references are not getting cleared by GC, it means the objects are at least softly reachable.

Clearing soft references is trickier, as this is up to the JVM's discretion. The only way to guarantee clearing of softly-reachable objects is to cause an OutOfMemoryError to be thrown. This trick is demonstrated in this discussion.

Ogata answered 6/8, 2011 at 16:31 Comment(1)
Isn't System.gc only a hint? And therefore isn't the answer to the question "no"?Toulouselautrec

© 2022 - 2024 — McMap. All rights reserved.