Skip to content
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

Memory leak when using Jersey with HK2 #5796

Open
albanf opened this issue Nov 11, 2024 · 7 comments
Open

Memory leak when using Jersey with HK2 #5796

albanf opened this issue Nov 11, 2024 · 7 comments

Comments

@albanf
Copy link

albanf commented Nov 11, 2024

When using Jersey and Jackson to deserialize XML, any change to the configuration of the WebTarget causes a memory leak since hk2 3.0.4 (and up to 3.1.1).

I suspect this is caused by this change in HK2: eclipse-ee4j/glassfish-hk2@9e5b5f5 (FISH-6432 Applications Take Longer To Deploy on JDK 17) since the same occurs with the patched Payara version 3.0.1.payara-p2 (payara/patched-src-hk2@3.0.1.payara-p1...3.0.1.payara-p2).

Not sure if this is a regression in HK2 or something that Jersey is doing incorrectly.

I've tested with Jersey version 3.0.0 to 3.1.9, and the behavior is the same.

See the attached example project.
jersey-memory-leak.zip

Also posted on HK2: eclipse-ee4j/glassfish-hk2#1126

@jbescos
Copy link
Member

jbescos commented Jan 28, 2025

I am analyzing the heap dump of that example. What instances are leaking?. There are 0 instances of org.example.jersey3.memoryleak.MyDTO.

Image

@albanf
Copy link
Author

albanf commented Jan 28, 2025

Hi @jbescos, look at class org.glassfish.client.ClientRuntime, you should expect 0 instances, but you see 100 instances.

@jbescos
Copy link
Member

jbescos commented Jan 28, 2025

One note, in your example you have:

        try (Client client = ClientBuilder.newClient()) {
            ...

            Runtime.getRuntime().gc();
            System.out.println("Ready for heap dump");
            Thread.sleep(20000);
            System.exit(0);
        }

That cannot release the clients, because it is inside the try block (#close was not invoked). It has to be in this way:

        try (Client client = ClientBuilder.newClient()) {
            ...
        }
        Runtime.getRuntime().gc();
        System.out.println("Ready for heap dump");
        Thread.sleep(20000);
        System.exit(0);

@jbescos
Copy link
Member

jbescos commented Jan 28, 2025

After modifying your example, I don't find org.glassfish.client.ClientRuntime instances. Could you check it too, please?.

@albanf
Copy link
Author

albanf commented Jan 28, 2025

If you consider a long running application, where a Client is instantiated then reused for many requests over a long period, then the code in my example is representative and shows that over time, the application will run out of memory.

@jbescos
Copy link
Member

jbescos commented Jan 28, 2025

Right, but I am not sure this is designed in that way.

From what I see, ClientRuntime is created for each request and in can be released in 2 ways:
1- Client#close
2- If there are no strong references to it (this case it seems it is not happening).

However, the point 2 is not good to happen because ClientRuntime#close is supposed to close the connector and it will be executed from GC threads. Tthis is not a good practice because it ignores exceptions, delays the GC, etc. For the default case of org.glassfish.jersey.client.internal.HttpUrlConnector it is a no-op, so it is not really a big issue.

Maybe I am wrong, but it looks it is an issue in the design. ClientRuntime should be discarded from memory after every request, and it should not have any onClose action. Connections should be released after Client#close or errors, limit of opened connections, etc.

@jbescos
Copy link
Member

jbescos commented Jan 30, 2025

It seems this was introduced here: #4508

If I revert it, there are 0 instances of ClientRuntime

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

3 participants