Export to GitHub

mockito - issue #470

Memory leak/Retained heap in RegisteredInvocations (LinkedList<Invocation> invocations)


Posted on Jan 23, 2014 by Grumpy Kangaroo

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 Monkey

Thanks we'll take a look.

Contributions are welcome :)

Comment #2

Posted on Jan 27, 2014 by Grumpy Kangaroo

Hierarchy : 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 Horse

In 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 Horse

There : https://github.com/mockito/mockito/blob/master/src/org/mockito/MockSettings.java#L233

Comment #5

Posted on Mar 4, 2014 by Grumpy Kangaroo

Hi 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 Horse

nope 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