-
Notifications
You must be signed in to change notification settings - Fork 1.9k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Classloader leaks from ShutdownThread and QueuedThreadPool #5859
Comments
@VasilVasilev93 I believe the classloader pinning by the WebSocketClient instance is being fixed in PR #5840, but perhaps @lachlan-roberts can comment more about that? As for the QueuedThreadPool contextClassLoader, I'll take a look at that, or we'd be happy to review a PR if you want to submit one? |
I don't think this is related to PR #5840, that PR is for jetty 10 and is the Javax client But in Jetty 9.4 the You should be able to avoid any issues associated with the shutdown thread by explicitly calling WebSocketClient client = new WebSocketClient();
client.setStopAtShutdown(false);
client.start(); |
@lachlan-roberts Uhm, the problem is not related to how
|
@VasilVasilev93 for the QueuedThreadPool: as a request handling thread drains out of a context, its context classloader is reset, so I'm not sure why the bundle classloader is still seen on the thread? |
@janbartel Is this happening somewhere outside the QueuedThreadPool class? |
@VasilVasilev93 yes, this happens in ContextHandler when a request is leaving a context, see: https://github.com/eclipse/jetty.project/blob/jetty-10.0.x/jetty-server/src/main/java/org/eclipse/jetty/server/handler/ContextHandler.java#L1287 The above link is for jetty-10, but it's the same code for jetty-9. It would be interesting if you could find out more about the thread in QueuedThreadPool that still had the classloader associated with it. |
@janbartel Thanks, I will check this out, and I will upload screenshots from eclipse memory analyzer later |
@janbartel I tested the above, it is working as you say, the classloader is reset indeed, but the issue here is that the thread is instantiated with the bundle's classloader and after the bundle gets uninstalled, the thread is still holding it. |
@VasilVasilev93 interesting. We will have to take a look in a non-osgi environment: presumably the thread's contextClassLoader would still be that of a context that had been undeployed .... How are you running jetty with osgi? Are you starting an osgi container from with a webapp or are you starting an osgi container and then starting jetty within it? |
@janbartel Starting jetty within an osgi container. |
@VasilVasilev93 ah hah! There are circumstances in which a queued thread pool thread is inside a context (thus with that context's classloader set on it), and it then creates another thread pool thread because all threads are currently busy. According to the constructor of Thread, a thread will inherit the context classloader of the thread that created it - in this case it would be the context's classloader and voila, classloader leak! The fix we're considering is to ensure that every thread that the QueuedThreadPool creates has it's classloader set explicitly to something safe like so: @Override
public Thread newThread(Runnable runnable)
{
Thread thread = new Thread(_threadGroup, runnable);
thread.setDaemon(isDaemon());
thread.setPriority(getThreadsPriority());
thread.setName(_name + "-" + thread.getId());
thread.setContextClassLoader(QueuedThreadPool.class.getClassLoader()); // add this line!
return thread;
} Is there any chance you could try this code out in your environment and report back if it solves the problem? |
@janbartel Yes, this is ok and it seems logical, I have it tested, it's working. |
Signed-off-by: Jan Bartel <[email protected]>
Signed-off-by: Jan Bartel <[email protected]>
@VasilVasilev93 excellent! I've raised #5894 with this fix. I'll do a separate PR for the ShutdownThread. |
Signed-off-by: Jan Bartel <[email protected]>
Okay, thanks :) |
@VasilVasilev93 re-reading the problem reported with the ShutdownThread, it seems to me that the QueuedThreadPool threads should also suffer from the retention of the inheritedAccessControlContext and it's associated ProtectionDomains, and hence the pinning of the contextClassLoader. Is this not the case? |
@janbartel In our specific case it doesn't cause issues, but yes, I believe so. |
Signed-off-by: Jan Bartel <[email protected]>
Signed-off-by: Jan Bartel <[email protected]>
Signed-off-by: Jan Bartel <[email protected]>
Signed-off-by: Jan Bartel <[email protected]>
Signed-off-by: Jan Bartel <[email protected]>
Signed-off-by: Jan Bartel <[email protected]>
* Issue #5859 Fix Classloader leak from QueuedThreadPool Signed-off-by: Jan Bartel <[email protected]>
Fixed via PR #5894 |
Signed-off-by: Joakim Erdfelt <[email protected]>
Jetty version
9.4.35.v20201120
Description
Hello, when running inside
osgi
environment, both classes allow classloader leaks. I noticed the leaks when using jetty'sWebSocketClient
from a bundle. After uninstall of the bundle, and of course cleaning up theWebSocketClient
instance, its classloader remains referenced insideShutdownThread
's inheritedAccessControlContext protection domain.Locally I made a change insideShutdownThread
class, to create the thread inside adoPrivileged
block, which fixed the issue.As for
QueuedThreadPool
, when a thread from the pool is used by a bundle, after its uninstall, the thread'scontextClassLoader
remains the bundle classloader, which creates a leak, until the thread gets reused by some other bundle. I made a local change to the class, to reset thecontextClassLoader
after the thread is marked as idle, which fixed the issue.The text was updated successfully, but these errors were encountered: