
mockito - issue #470
Memory leak/Retained heap in RegisteredInvocations (LinkedList<Invocation> invocations)
What steps will reproduce the problem?
I can easily reproduce the problem while using Mockito with Arquillian because it is storing class references to ThreadLocal(s) which stores also reference to Arquillian CDIExtension which then hold reference to BeanManager which then holds whole deployment in memory.
Saying that the problem is not related to Arquillian (just a quicker way to throw OOM) so you can reproduce the problem with a simple test.
As you can see below, ModuleClassLoaders trace back to thread locals that Mockito has set on FinalizerThreads:
Class Name | Ref. Objects | Shallow Heap | Ref. Shallow Heap | Retained Heap
java.lang.ref.Finalizer$FinalizerThread @ 0xaed98860 Finalizer Thread | 1 | 104 | 88 | 15,528 '- threadLocals java.lang.ThreadLocal$ThreadLocalMap @ 0xaed98910 | 1 | 24 | 88 | 15,336 '- table java.lang.ThreadLocal$ThreadLocalMap$Entry[16] @ 0xaed98928 | 1 | 80 | 88 | 15,312 '- [6] java.lang.ThreadLocal$ThreadLocalMap$Entry @ 0xc51c0318 | 1 | 32 | 88 | 5,008 '- value org.mockito.internal.progress.MockingProgressImpl @ 0xc51c0338 | 1 | 40 | 88 | 4,976 '- <class> class org.mockito.internal.progress.MockingProgressImpl @ 0xc35c9538| 1 | 8 | 88 | 8
'- <classloader> org.jboss.modules.ModuleClassLoader @ 0xba2a3e98 | 1 | 88 | 88 | 138,490,072
Class Name | Shallow Heap | Retained Heap
java.lang.ref.Finalizer$FinalizerThread @ 0x781503c08 Finalizer Native Stack, Thread | 104 | 19 942 048 |- <class> class java.lang.ref.Finalizer$FinalizerThread @ 0x781a52678 System Class | 0 | 0 |- blockerLock java.lang.Object @ 0x780308900 | 16 | 16 |- threadLocals java.lang.ThreadLocal$ThreadLocalMap @ 0x780308910 | 24 | 19 941 856 | |- <class> class java.lang.ThreadLocal$ThreadLocalMap @ 0x78407d858 System Class | 8 | 8 | |- table java.lang.ThreadLocal$ThreadLocalMap$Entry[32] @ 0x7b7980308 | 144 | 19 941 832 | | |- <class> class java.lang.ThreadLocal$ThreadLocalMap$Entry[] @ 0x781a66e60 | 0 | 0 | | |- [28] java.lang.ThreadLocal$ThreadLocalMap$Entry @ 0x780308928 | 32 | 32 | | |- [21] java.lang.ThreadLocal$ThreadLocalMap$Entry @ 0x780308948 | 32 | 32 | | |- [9] java.lang.ThreadLocal$ThreadLocalMap$Entry @ 0x798975400 | 32 | 5 200 | | |- [14] java.lang.ThreadLocal$ThreadLocalMap$Entry @ 0x7989754d0 | 32 | 72 | | |- [16] java.lang.ThreadLocal$ThreadLocalMap$Entry @ 0x798975518 | 32 | 48 | | |- [4] java.lang.ThreadLocal$ThreadLocalMap$Entry @ 0x7992a4b00 | 32 | 48 | | |- [0] java.lang.ThreadLocal$ThreadLocalMap$Entry @ 0x7992a4b30 | 32 | 6 263 400 | | | |- <class> class java.lang.ThreadLocal$ThreadLocalMap$Entry @ 0x781a66670 System Class | 0 | 0 | | | |- queue java.lang.ref.ReferenceQueue$Null @ 0x783c4bf00 | 32 | 48 | | | |- referent java.lang.ThreadLocal @ 0x798c46c80 | 16 | 16 | | | |- value org.mockito.internal.progress.MockingProgressImpl @ 0x7992a4b50 | 40 | 6 263 368 | | | | |- <class> class org.mockito.internal.progress.MockingProgressImpl @ 0x798c5cf30 | 0 | 0 | | | | |- reporter org.mockito.exceptions.Reporter @ 0x7992a4b78 | 16 | 16 | | | | |- argumentMatcherStorage org.mockito.internal.progress.ArgumentMatcherStorageImpl @ 0x7992a4b88 | 16 | 104 | | | | |- iOngoingStubbing org.mockito.internal.stubbing.OngoingStubbingImpl @ 0x7ae68b788 | 16 | 6 263 208 | | | | | |- <class> class org.mockito.internal.stubbing.OngoingStubbingImpl @ 0x798c5e768 | 0 | 0 | | | | | |- invocationContainerImpl org.mockito.internal.stubbing.InvocationContainerImpl @ 0x798a32b38 | 32 | 6 263 192 | | | | | | |- <class> class org.mockito.internal.stubbing.InvocationContainerImpl @ 0x798c50e38 | 16 | 16 | | | | | | |- stubbed java.util.LinkedList @ 0x798a32b58 | 32 | 80 | | | | | | |- mockingProgress org.mockito.internal.progress.ThreadSafeMockingProgress @ 0x798a34cd0 | 16 | 16 | | | | | | |- answersForStubbing java.util.ArrayList @ 0x798a34ce0 | 24 | 80 | | | | | | |- registeredInvocations org.mockito.internal.verification.RegisteredInvocations @ 0x798a34d30| 16 | 6 251 088 | | | | | | | |- <class> class org.mockito.internal.verification.RegisteredInvocations @ 0x798c511a8 | 8 | 8
| | | | | | | |- invocations java.util.Collections$SynchronizedList @ 0x798a34d40 | 24 | 6 251 072
So looks like Mockito is setting thread locals that it is not properly cleaning up, leading to a leak from retained classloaders. I tried to call explicitly Mockito.clear() after and before each tests but the memory leak still persist.
What version of the product are you using? On what operating system? Mockito 1.9.5 Ubuntu 13.04
Please provide any additional information below.
Comment #1
Posted on Jan 27, 2014 by Massive MonkeyThanks we'll take a look.
Contributions are welcome :)
Comment #2
Posted on Jan 27, 2014 by Grumpy KangarooHierarchy : MockingProgressImpl > OngoingStubbingImpl > InvocationContainerImpl > DefaultRegisteredInvocations > LinkedList invocations
I think DefaultRegisteredInvocations should expose a clear() method to cleanup invocations. But the method Mockito.reset() calls resetOngoingStubbing() that set iOngoingStubbing to null. So I don't understand why invocations are retained in memory ?
Comment #3
Posted on Mar 4, 2014 by Happy HorseIn order to verify them, I believe the git repo has a fix for that allowing to create mocks for stubbing only, in the settings API.
Would that work for you ?
Cheers, Brice
Comment #4
Posted on Mar 4, 2014 by Happy HorseThere : https://github.com/mockito/mockito/blob/master/src/org/mockito/MockSettings.java#L233
Comment #5
Posted on Mar 4, 2014 by Grumpy KangarooHi Brice,
I didn't know about that feature... but that would not work for us because we need to verify the number of invocations.
If you want I can validate that I can't reproduce this issue when using stubOnly() ?
Comment #6
Posted on Mar 12, 2014 by Happy Horsenope it has been done already :)
This is obviously one of the trade-off of the verification after approach. Maybe Easymock can work better for you in this case.
Comment #7
Posted on Aug 5, 2014 by Happy Horse(No comment was entered for this change.)
Status: WontFix
Labels:
Type-Defect
Priority-Medium