From f2f54441b79bb6d44be7a5618540c79a6c2f147f Mon Sep 17 00:00:00 2001 From: fitermay Date: Wed, 28 Feb 2018 21:33:03 -0500 Subject: [PATCH 1/2] make values in TypeEvalContextBasedCache soft to let gc collect not-recently-used values --- .../python/psi/types/TypeEvalContextBasedCache.java | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/python/psi-api/src/com/jetbrains/python/psi/types/TypeEvalContextBasedCache.java b/python/psi-api/src/com/jetbrains/python/psi/types/TypeEvalContextBasedCache.java index cd094a073208..338adc7ccc45 100644 --- a/python/psi-api/src/com/jetbrains/python/psi/types/TypeEvalContextBasedCache.java +++ b/python/psi-api/src/com/jetbrains/python/psi/types/TypeEvalContextBasedCache.java @@ -20,9 +20,9 @@ import com.intellij.psi.util.CachedValueProvider; import com.intellij.psi.util.CachedValuesManager; import com.intellij.psi.util.PsiModificationTracker; import com.intellij.util.Function; +import com.intellij.util.containers.ContainerUtil; import org.jetbrains.annotations.NotNull; -import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; /** @@ -68,8 +68,9 @@ public final class TypeEvalContextBasedCache { return value; } final T newValue = myProvider.fun(context); - map.put(key, newValue); // ConcurrentMap guarantees happens-before so from this moment get() should work in other threads - return newValue; + T oldValue = + map.putIfAbsent(key, newValue);// ConcurrentMap guarantees happens-before so from this moment get() should work in other threads + return oldValue == null ? newValue : oldValue; } /** @@ -81,7 +82,7 @@ public final class TypeEvalContextBasedCache { public Result> compute() { // This method is called if cache is empty. Create new map for it. // Concurrent map allows several threads to call get and put, so it is thread safe but not atomic - final ConcurrentHashMap map = new ConcurrentHashMap<>(); + final ConcurrentMap map = ContainerUtil.createConcurrentSoftValueMap(); return new Result<>(map, PsiModificationTracker.MODIFICATION_COUNT); } } From 44d758b1dbfabae62a19de96046051ead667f579 Mon Sep 17 00:00:00 2001 From: fitermay Date: Wed, 28 Feb 2018 21:36:46 -0500 Subject: [PATCH 2/2] minor: anonymous ThreadLocal class -> ThreadLocal.withInitial minor benefit is avoiding a reference cycle from anonymous class to TypeEvalContext as anonymous inner classes always hold a reference to the containing class --- .../python/psi/types/TypeEvalContext.java | 16 +++------------- 1 file changed, 3 insertions(+), 13 deletions(-) diff --git a/python/psi-api/src/com/jetbrains/python/psi/types/TypeEvalContext.java b/python/psi-api/src/com/jetbrains/python/psi/types/TypeEvalContext.java index fba9dfdb38d8..2cfa83700986 100644 --- a/python/psi-api/src/com/jetbrains/python/psi/types/TypeEvalContext.java +++ b/python/psi-api/src/com/jetbrains/python/psi/types/TypeEvalContext.java @@ -47,18 +47,8 @@ public class TypeEvalContext { private final Map myEvaluated = new HashMap<>(); private final Map myEvaluatedReturn = new HashMap<>(); - private final ThreadLocal> myEvaluating = new ThreadLocal>() { - @Override - protected Set initialValue() { - return new HashSet<>(); - } - }; - private final ThreadLocal> myEvaluatingReturn = new ThreadLocal>() { - @Override - protected Set initialValue() { - return new HashSet<>(); - } - }; + private final ThreadLocal> myEvaluating = ThreadLocal.withInitial(HashSet::new); + private final ThreadLocal> myEvaluatingReturn = ThreadLocal.withInitial(HashSet::new); private TypeEvalContext(boolean allowDataFlow, boolean allowStubToAST, boolean allowCallContext, @Nullable PsiFile origin) { myConstraints = new TypeEvalConstraints(allowDataFlow, allowStubToAST, allowCallContext, origin); @@ -254,7 +244,7 @@ public class TypeEvalContext { } /** - * @return context constraints (see {@link com.jetbrains.python.psi.types.TypeEvalConstraints} + * @return context constraints (see {@link TypeEvalConstraints} */ @NotNull TypeEvalConstraints getConstraints() {