Hi,
The ThreadMessageContext use a thread local variable to keep the SCA context
to support ComponentContext/RequestContext injection as well as
ServiceReference deserialization.
Are you saying the thread local variable is not released? I searched the
usages of the ThreadMessageContext in our code, all 3 cases are like:
Message msgContext = ThreadMessageContext.getMessageContext(); // Get
existing value [1]
...
ThreadMessageContext.setMessageContext(msg); // Set to new value [2]
try {
...
} finally {
ThreadMessageContext.setMessageContext(msgContext); // Reset to old
value [3]
}
But [1] has some issues because it creates default value (I don't know why
it is not null).
protected synchronized Message initialValue() {
Message msg = new MessageImpl();
msg.setFrom(new EndpointReferenceImpl("/"));
return msg;
}
Is the dummy message leaking?
BTW, we are also missing a check in
org.apache.tuscany.sca.core.context.impl.CallableReferenceImpl.resolve().
else if (compositeActivator == null) { // Only get the composite activator
when it is not set, the current code always looks for the thread local which
is not performed
this.compositeActivator =
CompositeContext.getCurrentCompositeActivator();
if (this.compositeActivator != null) {
this.proxyFactory =
this.compositeActivator.getCompositeContext().getProxyFactory();
}
}
We should fix that too.
Thanks,
Raymond
--------------------------------------------------
From: "Simon Laws" <[email protected]>
Sent: Thursday, July 23, 2009 5:51 AM
To: "tuscany-dev" <[email protected]>
Subject: [1.x] memory leak in binding.jsonrpc - some help required
I'm looking at TUSCANY-3173 and and the memory leak appears to relate
to some thread local storage we use relating to service proxies. In
the start() method of the JSONRPCServiceBindingProvider is the
following code...
public void start() {
// Set default databinding to json
serviceContract.getInterface().resetDataBinding(JSONDataBinding.NAME);
// Determine the service business interface
Class<?> serviceInterface =
getTargetJavaClass(serviceContract.getInterface());
// Create a Java proxy to the target service
** Object proxy =
component.getComponentContext().createSelfReference(serviceInterface,
service).getService();
// Create and register a Servlet for this service
JSONRPCServiceServlet serviceServlet =
new JSONRPCServiceServlet(messageFactory, binding,
service, serviceContract, serviceInterface, proxy);
The line I've marked with ** create and SCA service proxy and then
passed it into the servlet. Under the covers this proxy object finds
it's way into the JSONRPC library and is used to identify available
methods for the service etc.
In the case of the memory leak is happening a typical reference chain
for the WebAppClassloader is..
--> com.ctc.wstx.api.wstxinputproperties$parsingm...@0x3252888 (8 bytes)
(??:)
--> class com.ctc.wstx.api.WstxInputProperties$ParsingMode (84 bytes)
(??:)
--> org.apache.catalina.loader.webappclassloa...@0x320abe8 (152 bytes)
(field system:)
--> sun.misc.launcher$appclassloa...@0x2f17f00 (63 bytes) (field classes:)
--> java.util.vec...@0x2f21450 (24 bytes) (field elementData:)
--> [Ljava.lang.Object;@0x2f289c8 (88 bytes) (Element 0 of
[Ljava.lang.Object;@0x2f289c8:)
--> class org.apache.catalina.startup.Bootstrap (84 bytes) (static
field daemon:)
--> org.apache.catalina.startup.bootst...@0x2f17dd0 (24 bytes) (field
catalinaDaemon:)
--> org.apache.catalina.startup.catal...@0x2f33cd8 (101 bytes) (field
shutdownHook:)
--> org.apache.catalina.startup.catalina$catalinashutdownh...@0x3140790
(108 bytes) (field group:)
--> java.lang.threadgr...@0x2f17a10 (43 bytes) (field threads:)
--> [Ljava.lang.Thread;@0x319fa48 (72 bytes) (Element 10 of
[Ljava.lang.Thread;@0x319fa48:)
--> java.lang.thr...@0x31c9700 (104 bytes) (field threadLocals:)
--> java.lang.threadlocal$threadlocal...@0x31ce738 (20 bytes) (field
table:)
--> [Ljava.lang.ThreadLocal$ThreadLocalMap$Entry;@0x3313318 (136
bytes) (Element 11 of
[Ljava.lang.ThreadLocal$ThreadLocalMap$Entry;@0x3313318:)
--> java.lang.threadlocal$threadlocalmap$en...@0x33132d8 (28 bytes)
(field value:)
--> org.apache.tuscany.sca.core.invocation.messagei...@0x33139a0 (37
bytes) (??:)
--> class org.apache.tuscany.sca.core.invocation.MessageImpl (84 bytes)
(??:)
--> org.apache.catalina.loader.webappclassloa...@0x32aad98 (152 bytes)
The following stack, from proxy creation, is therefore of interest (I
was just using the store node to generate this as I know it uses
JSONRPC)...
Thread [main] (Suspended (breakpoint at line 46 in MessageImpl))
MessageImpl.<init>() line: 46
ThreadMessageContext$1.initialValue() line: 34
ThreadMessageContext$1.initialValue() line: 31
ThreadMessageContext$1(ThreadLocal<T>).setInitialValue() line: 141
ThreadMessageContext$1(ThreadLocal<T>).get() line: 131
ThreadMessageContext.getMessageContext() line: 70
ComponentContextHelper.getCurrentComponent() line: 264
ComponentContextHelper.getCurrentCompositeActivator() line: 277
ServiceReferenceImpl<B>(CallableReferenceImpl<B>).resolve() line: 374
ServiceReferenceImpl<B>(CallableReferenceImpl<B>).getService() line: 209
JSONRPCServiceBindingProvider.start() line: 99
CompositeActivatorImpl$3.run() line: 630
AccessController.doPrivileged(PrivilegedAction<T>) line: not
available [native method]
CompositeActivatorImpl.start(Component) line: 628
CompositeActivatorImpl.start(Composite) line: 560
NodeImpl.start() line: 716
NodeImplementationLauncherBootstrap$NodeFacade.start() line: 56
NativeMethodAccessorImpl.invoke0(Method, Object, Object[]) line: not
available [native method]
NativeMethodAccessorImpl.invoke(Object, Object[]) line: 39
DelegatingMethodAccessorImpl.invoke(Object, Object[]) line: 25
Method.invoke(Object, Object...) line: 597
NodeLauncher.main(String[]) line: 139
LaunchStoreNode.main(String[]) line: 26
To save myself a lot of time working out what is going on can someone
explain what the ThreadMessageContext is doing here and why there is a
static context in that class.
When I comment out line ** and pass null into the servlet I don't get
the memory leak.
Regards
Simon