-
Notifications
You must be signed in to change notification settings - Fork 38.8k
Description
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.- Several tests with different application contexts or tests which dirty the application context => what matters is that application contexts get built often.
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
- OS: Mac OS X 10.9.1
- Java Versions:
JDK Version 1.6 1.6.0_65-b14-462-11M4609 1.7 1.7.0_51-b13 1.8 1.8.0-b129 - Time: in minutes
- Classes: represent the number of classes loaded.
- Memory: values are rounded and represent Used/Size/Max memory * 1,000,000 Bytes. For JDK 1.6 and 1.7, memory represents PermGen usage. For JDK 1.8, memory represents Metaspace usage.
Conclusion
As can be seen in the Analysis section, the fixes in Spring Framework 3.2.8.BUILD-SNAPSHOT
and 4.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:
- memory usage - JDK 1.6 - Spring 3.2.7.png (73.16 kB)
- memory usage - JDK 1.6 - Spring 4.0.2.png (61.34 kB)
- memtest.zip (92.08 kB)
Issue Links:
- Inclusion of
overloaded
inequals()
andhashCode()
forMethodOverride
breaksequals()
inAbstractBeanDefinition
[SPR-11420] #16047 Inclusion of 'overloaded' in equals() and hashCode() for MethodOverride breaks equals() in AbstractBeanDefinition ("depends on") - MemoryLeak in Cglib2AopProxy.ProxyCallbackFilter [SPR-8008] #12663 MemoryLeak in Cglib2AopProxy.ProxyCallbackFilter
- Inclusion of
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 heap [SPR-11275] #15899
@Async
with cglib based proxy causes memory leak in heap - Add ability to create proxy around classes that has no default constructor [SPR-10594] #15223 Add ability to create proxy around classes that has no default constructor
Referenced from: commits 8028eae, 1ae3eba, f2a4537, bc87910
Backported to: 3.2.8