-
Notifications
You must be signed in to change notification settings - Fork 38.5k
Method injection causes memory leak [SPR-10785] #15411
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
Sam Brannen commented Hi Christian, Thanks for putting together the project for reproducing this behavior. On a Mac, I was not able to reproduce the problem with JDK 7 or JDK 8 running against Spring Framework 4.0.2 (snapshot); however, I was able to reproduce it when running against JDK 6 on the same machine. Thus it appears to chiefly be an issue with garbage collection in the JVM for Java 6. However, the core of the issue likely lies in the fact that CGLIB is used to dynamically create subclasses of the bean class for which the method is injected. Specifically, the two variants of We will continue to investigate the issue. Regards, Sam |
Sam Brannen commented This potentially relates to #15899 in terms of recreation of identical CGLIB proxy classes. |
Sam Brannen commented In case you're interested, I have pushed some work I've been doing on this issue to the following branch: https://github.com/sbrannen/spring-framework/commits/SPR-10785 There are a few things to fine tune, but in general this approach seems to take care of the memory leaks associated with method injection. |
Sam Brannen commented Resolving this issue as Fixed. The fix was actually performed as a positive side-effect of #16047; however, I am leaving this issue assigned to both 3.2.8 and 4.0.2 since the issue summary is more explanatory than that for #16047. |
Sam Brannen commented Although this issue has been fixed (see the Analysis and Conclusion sections above), we would like to point out that the Spring Team no longer recommends heavy usage of method injection. As a modern alternative to method injection, please consider using the |
Piotr Findeisen commented Hi,
Of course, for every found case of this problem, the fix is as simple as moving the ctor code to |
Sam Brannen commented Since this is a closed issue, would you please create a new JIRA issue describing your findings? Please also mention this issue in the new issue's description, and feel free to assign the issue to me. Thanks! Sam |
Piotr Findeisen commented Sam Brannen, |
Sam Brannen commented Makes sense. Thanks for the feedback! |
Christian Schreder opened SPR-10785 and commented
Overview
Recently I recognized strange behavior in a project with around 700 tests running via Maven in one JVM. Some of the tests have different application contexts defined. As I run the tests I get an
OutOfMemoryException
. I managed to break it down to one place where a bean with method injection is defined. If I comment it out I have constant memory usage. With it, memory consumption is increasing. Reproduced on Windows 7 using JRockit 1.6.For further investigation I wrote a reproducer. It is a simple maven project defining two beans where one bean has a method injection. I have 4 test classes with 1000 test methods per class and after each method the application context is rebuilt (via the
@DirtiesContext
annotation). Also I included a log file with activated gc-logging. I was also able to reproduce this behavior on Mac OS 10.6.8 with Sun's JDK 1.6.Assumptions
ApplicationContext
with method injection.Steps to Reproduce
Run all tests in one JVM (e.g. with maven).
Result
Memory consumption constantly increases until an
OutOfMemoryException
is thrown.Analysis
The following table displays execution time, the number of classes loaded, and memory consumption when the test suite in the attached ZIP file are executed against various Java and Spring versions.
Spring 3.2.x
|| Spring Version || Java Version || Time || Classes || Memory |
|
3.2.7.RELEASE
| JDK 1.6 | 1:54 | 6700 | 54 / 86 / 86 ||
3.2.7.RELEASE
| JDK 1.7 | 1:51 | 6629 | 45 / 82 / 86 ||
3.2.7.RELEASE
| JDK 1.8 | 1:44 | 6670 | 43 / 44 / 1082 ||
3.2.8.BUILD-SNAPSHOT
| JDK 1.6 | 1:42 | 2716 | 21 / 22 / 86 ||
3.2.8.BUILD-SNAPSHOT
| JDK 1.7 | 1:31 | 2629 | 17 / 22 / 86 ||
3.2.8.BUILD-SNAPSHOT
| JDK 1.8 | 1:24 | 2683 | 17 / 18 / 1082 |Spring 4.0.x
|| Spring Version || Java Version || Time || Classes || Memory |
|
4.0.1.RELEASE
| JDK 1.6 | 2:27 | 6761 | 54 / 83 / 86 ||
4.0.1.RELEASE
| JDK 1.7 | 2:22 | 6681 | 46 / 78 / 86 ||
4.0.1.RELEASE
| JDK 1.8 | 2:09 | 6739 | 43 / 44 / 1082 ||
4.0.2.BUILD-SNAPSHOT
| JDK 1.6 | 1:38 | 2758 | 22 / 22 / 86 ||
4.0.2.BUILD-SNAPSHOT
| JDK 1.7 | 1:56 | 2675 | 17 / 22 / 86 ||
4.0.2.BUILD-SNAPSHOT
| JDK 1.8 | 1:39 | 2741 | 18 / 19 / 1082 |Key
Conclusion
As can be seen in the Analysis section, the fixes in Spring Framework
3.2.8.BUILD-SNAPSHOT
and4.0.2.BUILD-SNAPSHOT
result in constant memory consumption and zero unnecessary CGLIB class generation (i.e., no longer one CGLIB class per method injected bean instance).The following screenshots provide a visual comparison for Java 6.
Before Fix (Spring 3.2.7)
!memory usage - JDK 1.6 - Spring 3.2.7.png|thumbnail!
After Fix (Spring 4.0.2)
!memory usage - JDK 1.6 - Spring 4.0.2.png|thumbnail!
Affects: 3.0 GA
Attachments:
Issue Links:
overloaded
inequals()
andhashCode()
forMethodOverride
breaksequals()
inAbstractBeanDefinition
[SPR-11420] #16047 Inclusion of 'overloaded' in equals() and hashCode() for MethodOverride breaks equals() in AbstractBeanDefinition ("depends on")overloaded
inequals()
andhashCode()
forMethodOverride
breaksequals()
inAbstractBeanDefinition
[SPR-11420] #16047 Inclusion of 'overloaded' in equals() and hashCode() for MethodOverride breaks equals() in AbstractBeanDefinition@Async
with cglib based proxy causes memory leak in heapReferenced from: commits 8028eae, 1ae3eba, f2a4537, bc87910
Backported to: 3.2.8
The text was updated successfully, but these errors were encountered: