-
Notifications
You must be signed in to change notification settings - Fork 5.3k
Reducing memory usage while evaluating reflective EL expressions #770
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
Conversation
|
I was also surprised recently to discover that the JVM does not cache results of So there is a (positive) GC impact of this change as well. |
|
Any caching approach needs to consider the case of two classes in different web applications with the same name but different structures. Essentially, caching needs to be per class loader. |
|
I'd also like to see the key remove from the cache when the value expires. |
+1 So I think your technique @jengebr is good, but the cache just needs to be pulled-up into the application scope or similar. Definitely don't cache directly in the Util class. It probably needs to be in a class that is loaded into the application's ClassLoader to be as clean as possible. Actually, I think we must not change the |
|
Thanks, I get your points about caching scope and cleanup. @ChristopherSchultz what prevents changes to |
|
I think the changes will have to go into |
|
This complexity led me to try a fallback plan, which can be faster: if the method has zero parameters, retrieve the Method by name. This works because there is no confusion about parameter types. Example: Test data shows this is 2x faster than caching for the fast case, and has no appreciable impact on the others. That's an excellent outcome for my application, not sure how you feel about the general case? |
That package and class don't "belong" to us, they belong to JavaEE/JakartaEE. Depending upon how it changes, we might fail the TCK. It's just better to put it in something under |
|
Actually, it does belong to us. It isn't part of the public API. We are free to change it how we wish. If you compare our version to the equivalent code in the EL API JAR from Jakarta EE there are various differences. |
|
I'm fine with the zero-arg optimisation. If others want the more general caching solution it can still be implemented. |
|
Changes are committed as discussed, ready for re-review. Specifically:
|
|
I'm planning on applying this manually to main and then back-porting. So far I've made the following changes:
Just running the full test suite before committing to check I haven't missed anything. |
When the method has no arguments there is no requirement to consider casting or coercion. Shortcut the method lookup process in that case. Based on PR #770 by John Engebretson.
When the method has no arguments there is no requirement to consider casting or coercion. Shortcut the method lookup process in that case. Based on PR #770 by John Engebretson.
When the method has no arguments there is no requirement to consider casting or coercion. Shortcut the method lookup process in that case. Based on PR #770 by John Engebretson.
When the method has no arguments there is no requirement to consider casting or coercion. Shortcut the method lookup process in that case. Based on PR #770 by John Engebretson.
|
Those were the only changes required. Fix applied to main, 11.0.1, 10.1.x and 9.0.x. |
|
Thank you so much! :) |
This change fixes https://bz.apache.org/bugzilla/show_bug.cgi?id=69381 by caching the JVM-provided
Method[]. The OpenJDK compiler creates duplicateMethodobjects on every call toClass.getMethods(), which is an expensive task that is only made worse on complex classes that have moreMethods.ClassLoader leaks are avoided by keying off the class' name (
String) and storing theMethod[]in aWeakReference<Method[]>. The cost of the concurrency is easily outweighed by the savings from not duplicating dozens of objects, as demonstrated from output in the modifiedTestELParserPerformanceprovided at the bottom of this PR body.Key points from the data:
Methods, but the growth is far less (4% vs 40%).Original:
Optimized: