Closed
Bug 281067
Opened 20 years ago
Closed 20 years ago
ThreadLocal in Context prevents class unloading
Categories
(Rhino Graveyard :: Core, defect)
Rhino Graveyard
Core
Tracking
(Not tracked)
RESOLVED
FIXED
People
(Reporter: szegedia, Assigned: igor)
Details
Attachments
(1 file)
6.11 KB,
patch
|
Details | Diff | Splinter Review |
User-Agent: Opera/7.54 (Windows NT 5.0; U) [en]
Build Identifier:
I have an environment where most of the system (including Rhino) is hot-
reloadable. The classes are loaded through a particular java.net.URLClassLoader,
and upon detecting a change, the class loader is thrown away, and a new one is
created, allowing for the classes to be reloaded. However, a small issue in
Rhino's Context class prevents the throwaway class loader (and all the classes
it loads) from being garbage collected, resulting in memory leak over time.
The issue is the ThreadLocal "Context[] storage". Since the type of the value in
ThreadLocal is org.mozilla.javascript.Context[], the class org.mozilla.
javascript.Context will remain permanently loaded, and will keep the class
loader from being garbage collected -- we're utilizing a permanent set of
threads, actually they're created by JMS sessions, so we can't just terminate
and restart the threads to get rid of the stuck thread locals. However, there is
a brilliantly simple solution - store an Object[] instead of Context[] in the
thread local. Granted, we sacrifice a bit of static type safety, but Rhino will
no longer prevent the class loader that loaded it from being garbage collected.
Patch on the way.
Reproducible: Always
Steps to Reproduce:
Reporter | ||
Comment 1•20 years ago
|
||
Patch attached
Assignee | ||
Comment 2•20 years ago
|
||
I thought that Java used week references to store ThreadLocal in Thread
instances. Apparently it does not which also means that even with the patch
after Rhino reloading all those ThreaLocal instances from reloaded Rhino classes
would stuck in memory forever.
Of cause it is much better then forever stuck Rhino classes themselves so I will
commit the patch after regression testing.
Status: NEW → ASSIGNED
Assignee | ||
Comment 3•20 years ago
|
||
I committed the patch.
BTW, since you repeatedly reload Rhino classes, did the patch address memory
leak completely on your JVM? Or do you still see some leaks like the one
described in
https://bugzilla.mozilla.org/show_bug.cgi?id=243305#c9 ?
Status: ASSIGNED → RESOLVED
Closed: 20 years ago
Resolution: --- → FIXED
Reporter | ||
Comment 4•20 years ago
|
||
(In reply to comment #3)
>
> BTW, since you repeatedly reload Rhino classes, did the patch address memory
> leak completely on your JVM? Or do you still see some leaks like the one
> described in
> https://bugzilla.mozilla.org/show_bug.cgi?id=243305#c9 ?
I'll run it through a profiler now (been profiling all day :-) ). However, what
you say is certainly true - the ThreadLocal object and the Object[] will get
stuck in the thread's local table... Hm... maybe in the end I'll really have to
introduce a feature for perodically shutting down and recreating the JMS
sessions...
Reporter | ||
Comment 5•20 years ago
|
||
(In reply to comment #3)
> I committed the patch.
>
> BTW, since you repeatedly reload Rhino classes, did the patch address memory
> leak completely on your JVM? Or do you still see some leaks like the one
> described in
> https://bugzilla.mozilla.org/show_bug.cgi?id=243305#c9 ?
No, I see no leaks now. As a matter of fact, Thread indeed holds the ThreadLocal
objects using weak references. However, weak references are defeated if the
value - directly or indirectly - refers back strongly to the key. In the case
with storing a Context[], we had a strong reference from value to key via the
path value = Context[] instance -> Context[].class -> Context.class -> Context.
threadLocalCx = key. Storing an Object[] instead of Context[] solved it for good
:-). Provided the array element is null (which is easy by using a Context.exit()
in a finally block), the ThreadLocal object can be fully garbage collected after
the Context class is unloaded.
Reporter | ||
Comment 6•20 years ago
|
||
Thinking about it, I believe it'd be necessary to provide a comment around
"storage = new Object[1];" explaining why do we use it instead of Context[] -
it's not immediately apparent, and some otherwise well-meaning soul (who comes
to maintain it sometime in the future after we all moved along) unsuspectingly
rewrites it back to Context[]...
Assignee | ||
Comment 7•20 years ago
|
||
(In reply to comment #5)
> As a matter of fact, Thread indeed holds the ThreadLocal
> objects using weak references. However, weak references are defeated if the
> value - directly or indirectly - refers back strongly to the key. In the case
> with storing a Context[], we had a strong reference from value to key via the
> path value = Context[] instance -> Context[].class -> Context.class -> Context.
> threadLocalCx = key.
But why the reference from Context.threadLocalCx prevents in your case Rhino
classes from garbage collection? If ThreadLocal value is reachable from Thread
only through week reference, it should allow to GC classes as long as the last
strong reference to them and their class loader is gone.
Reporter | ||
Comment 8•20 years ago
|
||
(In reply to comment #7)
>
> But why the reference from Context.threadLocalCx prevents in your case Rhino
> classes from garbage collection? If ThreadLocal value is reachable from Thread
> only through week reference, it should allow to GC classes as long as the last
> strong reference to them and their class loader is gone.
No, only the keys in the WeakHashMap are weakly reachable (in our case, the
ThreadLocal object). The values in WeakHashMap are strongly reachable. And if
the value is a Context[], it'll establish a strong reference to the ThreadLocal
key, as outlined in comment #5, preventing it to be GC-ed for the lifetime of
the thread.
Assignee | ||
Comment 9•20 years ago
|
||
(In reply to comment #8)
>... only the keys in the WeakHashMap are weakly reachable (in our case, the
> ThreadLocal object). The values in WeakHashMap are strongly reachable. And if
> the value is a Context[], it'll establish a strong reference to the ThreadLocal
> key, as outlined in comment #5, preventing it to be GC-ed for the lifetime of
> the thread.
I will add then comments about using Object[], not Context[] after I will finish
with bug 281247.
You need to log in
before you can comment on or make changes to this bug.
Description
•