Use SoftReferences for context caching in the TCF
Prior to this commit, the ContextCache in the Spring TestContext Framework (TCF) cached ApplicationContexts in a ConcurrentHashMap using strong references. This practice can occasionally lead to OutOfMemoryErrors when running a large number of tests in a test suite with varying context configuration since the context cache becomes overpopulated over time. This commit addresses this issue by using Spring's ConcurrentReferenceHashMap which uses SoftReferences for both the keys (i.e., MergedContextConfiguration instances) and values (i.e., ApplicationContexts) stored in the map that backs the ContextCache. Issue: SPR-7687
This commit is contained in:
parent
2a4f4cd258
commit
0cb22fc8f3
|
|
@ -21,7 +21,6 @@ import java.util.HashSet;
|
|||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
|
||||
import org.springframework.context.ApplicationContext;
|
||||
|
|
@ -29,14 +28,13 @@ import org.springframework.context.ConfigurableApplicationContext;
|
|||
import org.springframework.core.style.ToStringCreator;
|
||||
import org.springframework.test.annotation.DirtiesContext.HierarchyMode;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.ConcurrentReferenceHashMap;
|
||||
|
||||
/**
|
||||
* Cache for Spring {@link ApplicationContext ApplicationContexts} in a test
|
||||
* environment.
|
||||
*
|
||||
* <p>{@code ContextCache} maintains a cache of {@code ApplicationContexts}
|
||||
* keyed by {@link MergedContextConfiguration} instances.
|
||||
*
|
||||
* <h3>Rationale</h3>
|
||||
* <p>Caching has significant performance benefits if initializing the context
|
||||
* takes a considerable about of time. Although initializing a Spring context
|
||||
* itself is very quick, some beans in a context, such as a
|
||||
|
|
@ -44,9 +42,17 @@ import org.springframework.util.Assert;
|
|||
* time to initialize. Hence it often makes sense to perform that initialization
|
||||
* only once per test suite.
|
||||
*
|
||||
* <h3>Implementation Details</h3>
|
||||
* <p>{@code ContextCache} maintains a cache of {@code ApplicationContexts}
|
||||
* keyed by {@link MergedContextConfiguration} instances. Behind the scenes,
|
||||
* Spring's {@link ConcurrentReferenceHashMap} is used to store
|
||||
* {@linkplain java.lang.ref.SoftReference soft references} to cached contexts
|
||||
* and {@code MergedContextConfiguration} instances.
|
||||
*
|
||||
* @author Sam Brannen
|
||||
* @author Juergen Hoeller
|
||||
* @since 2.5
|
||||
* @see ConcurrentReferenceHashMap
|
||||
*/
|
||||
class ContextCache {
|
||||
|
||||
|
|
@ -54,7 +60,7 @@ class ContextCache {
|
|||
* Map of context keys to Spring {@code ApplicationContext} instances.
|
||||
*/
|
||||
private final Map<MergedContextConfiguration, ApplicationContext> contextMap =
|
||||
new ConcurrentHashMap<MergedContextConfiguration, ApplicationContext>(64);
|
||||
new ConcurrentReferenceHashMap<MergedContextConfiguration, ApplicationContext>(64);
|
||||
|
||||
/**
|
||||
* Map of parent keys to sets of children keys, representing a top-down <em>tree</em>
|
||||
|
|
@ -63,7 +69,7 @@ class ContextCache {
|
|||
* of other contexts.
|
||||
*/
|
||||
private final Map<MergedContextConfiguration, Set<MergedContextConfiguration>> hierarchyMap =
|
||||
new ConcurrentHashMap<MergedContextConfiguration, Set<MergedContextConfiguration>>(64);
|
||||
new ConcurrentReferenceHashMap<MergedContextConfiguration, Set<MergedContextConfiguration>>(64);
|
||||
|
||||
private final AtomicInteger hitCount = new AtomicInteger();
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue