-
Notifications
You must be signed in to change notification settings - Fork 38.4k
Java 17: resource.isReadable() with concurrency leaks large amounts of non-heap memory #30955
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
Comments
We have some further analysis to offer from the JDK side. We would like the Springboot project team to evaluate the feasibility of the change suggested below to ResourceUtils::useCachesIfNecessary, and implement it if possible. Issue Statement Methods org.springframework.core.io.UrlResource.isReadable() and org.springframework.c.t.c.SimpleMetadataReaderFactory.getMetadataReader(Resource resource) end up calling org.springframework.u.ResourceUtils.useCachesIfNecessary(URLConnection con), which calls sun.net.w.p.j.JarURLConnection.setUseCaches(false) for resources in Jar files. When isReadable and getMetadataReader then call JarURLConnection.connect(), there are no cached connections, and each JarURLConnection for a particular Jar file gets its own, additional, j.u.z.Inflater instance with a reference to an off-heap buffer. Modern Java reference handling delays collection of these buffers for two gc cycles after use, and even then the glibc per-thread malloc() cache retains the memory after it’s been free()’d. These buffers are in addition to the per-jar buffer created in order to provision the MRJAR feature introduced in Java 9 (JEP 238). In large Springboot applications which call either of these methods for the jar population, the extra RSS usage for these j.u.z.Inflater buffers can amount to tens of gigabytes. In a Linux environment where Xmx == Xms, swap is disabled, and the RSS budget is tight, this risks the process being reaped by the OOM killer. We have shown, by patching JarURLConnection.setUseCaches to ignore a false setting, that not setting useCaches to false for a JarURLConnection is sufficient to avoid RSS growth. However, this change of the API's behavior is not an acceptable solution. Two Workarounds and a Proposed Resolution
Disclaimer We are not aware of the origin of or justification for the JarURLConnection.setUseCaches(false) call in ResourceUtils.useCachesIfNecessary(), and can only speculate. |
|
I can indeed reproduce with Spring Boot 3.2.0-RC2 and Spring Framework 6.1.0 and confirm this change make a huge difference in term of RSS consumption. |
This is now fixed on @peterdnight I have not been able to reproduce with Spring Framework 6.0, so for now no backport is planned. I suspect this could be related to the fact the issue happen only with multi release JARs (which is the case for Spring Framework 6.1 JARs but not 6.0 JARs). Maybe your repro was using multi release JARs in the application dependencies. Feel free to send a Spring Boot 3.1 + Framework 6.0 self contained repro as an attached archive or a Git repository if you want us to reconsider if we should backport or not. If possible, I think we would like to keep this change 6.1 only to avoid unwanted side effects on existing deployments. |
Scenario:
To reproduce:
Stacktrace:
Controller:
The text was updated successfully, but these errors were encountered: