forked from mockito/mockito
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Fixes mockito#1614: Add API to clean up mocks.
Due to the introduction of map from weak reference from mock instance to its invocation handler, Mockito became vunerable to memory leaks as there are multiple situations where Mockito could unintentionally hold strong references to mock instances in the map record. The strong references could be through spiedInstance for spies, and arguments used to faciliate method stubbing. Mockito could never know if the arguments passed in for method stubbing are also strongly referenced somewhere else or not, so Mockito needs to save a strong reference to these arguments to avoid premature GC. Therefore to solve cyclic strong references through arguments Mockito needs to explicitly know when mocks are out of their life, and clean up all internal strong references associated with them. This commit also fixes mockito#1532 and fixes mockito#1533.
- Loading branch information
Showing
8 changed files
with
210 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
/* | ||
* Copyright (c) 2019 Mockito contributors | ||
* This program is made available under the terms of the MIT License. | ||
*/ | ||
|
||
package org.mockito.plugins; | ||
|
||
import org.mockito.Incubating; | ||
|
||
/** | ||
* Extension to {@link MockMaker} for mock makers that changes inline method implementations. | ||
* @since 2.24.8 | ||
*/ | ||
@Incubating | ||
public interface InlineMockMaker extends MockMaker { | ||
/** | ||
* Cleans up internal state for specified {@code mock}, or all existing mocks if {@code mock} is {@code null}. You | ||
* may assume there won't be any interaction to mocks which internal state are cleaned after this is called. | ||
* | ||
* @param mock the mock instance whose internal state is to be cleaned, or {@code null} to clean all existing mocks. | ||
* @since 2.24.8 | ||
*/ | ||
@Incubating | ||
void cleanUpMock(Object mock); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
39 changes: 39 additions & 0 deletions
39
...s/inline/src/test/java/org/mockitoinline/bugs/CyclicMockMethodArgumentMemoryLeakTest.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,39 @@ | ||
/* | ||
* Copyright (c) 2019 Mockito contributors | ||
* This program is made available under the terms of the MIT License. | ||
*/ | ||
|
||
package org.mockitoinline.bugs; | ||
|
||
import org.junit.Test; | ||
|
||
import static org.mockito.Mockito.framework; | ||
import static org.mockito.Mockito.mock; | ||
|
||
public class CyclicMockMethodArgumentMemoryLeakTest { | ||
private static final int ARRAY_LENGTH = 1 << 20; // 4 MB | ||
|
||
@Test | ||
public void no_memory_leak_when_cyclically_calling_method_with_mocks() { | ||
for (int i = 0; i < 100; ++i) { | ||
final A a = mock(A.class); | ||
a.largeArray = new int[ARRAY_LENGTH]; | ||
final B b = mock(B.class); | ||
|
||
a.accept(b); | ||
b.accept(a); | ||
|
||
framework().clearAllMocks(); | ||
} | ||
} | ||
|
||
private static class A { | ||
private int[] largeArray; | ||
|
||
void accept(B b) {} | ||
} | ||
|
||
private static class B { | ||
void accept(A a) {} | ||
} | ||
} |
35 changes: 35 additions & 0 deletions
35
subprojects/inline/src/test/java/org/mockitoinline/bugs/SelfSpyReferenceMemoryLeakTest.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,35 @@ | ||
/* | ||
* Copyright (c) 2019 Mockito contributors | ||
* This program is made available under the terms of the MIT License. | ||
*/ | ||
|
||
package org.mockitoinline.bugs; | ||
|
||
import org.junit.Test; | ||
|
||
import static org.mockito.Mockito.framework; | ||
import static org.mockito.Mockito.spy; | ||
|
||
public class SelfSpyReferenceMemoryLeakTest { | ||
private static final int ARRAY_LENGTH = 1 << 20; // 4 MB | ||
|
||
@Test | ||
public void no_memory_leak_when_spy_holds_reference_to_self() { | ||
for (int i = 0; i < 100; ++i) { | ||
final DeepRefSelfClass instance = spy(new DeepRefSelfClass()); | ||
instance.refInstance(instance); | ||
|
||
framework().clearAllMocks(); | ||
} | ||
} | ||
|
||
private static class DeepRefSelfClass { | ||
private final DeepRefSelfClass[] array = new DeepRefSelfClass[1]; | ||
|
||
private final int[] largeArray = new int[ARRAY_LENGTH]; | ||
|
||
private void refInstance(DeepRefSelfClass instance) { | ||
array[0] = instance; | ||
} | ||
} | ||
} |