uhm.. I see why this might get a bit heavy - probably good to be helping the gc a tiny bit with that remove then.
and with 10e6 calls (I assume not 10e6 threads) you would also be exercising that hash map in ThreadLocalMap (but it should perform well, just ~ 20 resizes) .. but how is this related to Jena? ;-) On 17 March 2015 at 13:45, Andy Seaborne <[email protected]> wrote: > The weak reference might explain one of the problems I had when running 10e6 > tests. (I find them unpredictable but that might be because I avoid them so > it's circular.) > > The heap was growing unexpectedly as it was keeping things around, and into > the long term area, when I thought they were open to GC'ing. In the end, I > manually cleared the ThreadLocal value as well as removing it, kept the heap > size constant, the long term area small, and no major GCs. > > Andy > > > On 17/03/15 12:01, Stian Soiland-Reyes wrote: >> >> On 17 March 2015 at 11:33, Andy Seaborne <[email protected]> wrote: >>> >>> I've ended up in a new system [*] heavily depending on ThreadLocals to >>> manage transaction state. I did discover you have to carefully remember >>> to >>> .remove them; they are quite chunky and have non-GC state. >>> >>> Has anyone got any other practical advice or using them? Performance >>> implications? >> >> >> I've used them a lot. They should go when the Thread dies. So if you >> use Thread pools it gets a bit trickier.. but the ThreadLocalMap uses >> WeakReferences - so if your reference to the ThreadLocal goes out of >> scope, then it should also (eventually) be GC-ed. >> >> >> * <p>Each thread holds an implicit reference to its copy of a >> thread-local >> * variable as long as the thread is alive and the <tt>ThreadLocal</tt> >> * instance is accessible; after a thread goes away, all of its copies of >> * thread-local instances are subject to garbage collection (unless other >> * references to these copies exist). >> >> >> >> >> Here's how I used it to get thread-safe JAXB marshallers.. probably a >> bit awkward. >> >> >> https://github.com/apache/incubator-taverna-language/blob/master/taverna-scufl2-t2flow/src/main/java/org/apache/taverna/scufl2/translator/t2flow/T2FlowParser.java >> >> >> Here's the JDK's implementation: (GPLv3): >> >> >> >> https://github.com/stain/jdk8u/blob/master/src/share/classes/java/lang/ThreadLocal.java#L161 >> >> The ThreadLocalMap is kept as a field of the Thread: >> >> >> https://github.com/stain/jdk8u/blob/master/src/share/classes/java/lang/ThreadLocal.java#L232 >> >> and it has weak references back again to the ThreadLocal within the >> entry that keeps the value >> >> https://github.com/stain/jdk8u/blob/master/src/share/classes/java/lang/ThreadLocal.java#L298 >> >> so the values should stay alive as long as both the ThreadLocal is >> other-wise reachable, and the Thread is still alive (and you have not >> called that ThreadLocal.remove() button) >> >> >> >> I've not seen any performance issues - that it can do lazily >> initialization of the value per thread is quite nice. If you see in >> the ThreadLocalMap above you see the tables are quite light-weight, >> optimized for Threads not usually having many ThreadLocals. >> >> >> >>> >>> Andy >>> >>> [*] WIP: It's public on my github account. >>> >> >> You are not going to lure me in! >> >> > -- Stian Soiland-Reyes Apache Taverna (incubating), Apache Commons RDF (incubating) http://orcid.org/0000-0001-9842-9718
