Optimize memory usage by LockBasedStorageManager inner classes

Change all inner classes to be 'static'
Use explicit reference to StorageManager instead of
implicit reference to outer class.

The main problem of inner classes here is that outer instance
is being captured at each inheritance level, so e.g. some lazy value impls
may store up to three duplicating references.
This commit is contained in:
Denis Zharkov
2016-04-30 12:09:06 +03:00
parent 09509b6d18
commit 594fa02a9c
@@ -111,7 +111,7 @@ public class LockBasedStorageManager implements StorageManager {
@NotNull Function1<? super K, ? extends V> compute,
@NotNull ConcurrentMap<K, Object> map
) {
return new MapBasedMemoizedFunctionToNotNull<K, V>(map, compute);
return new MapBasedMemoizedFunctionToNotNull<K, V>(this, map, compute);
}
@NotNull
@@ -126,13 +126,13 @@ public class LockBasedStorageManager implements StorageManager {
@NotNull Function1<? super K, ? extends V> compute,
@NotNull ConcurrentMap<K, Object> map
) {
return new MapBasedMemoizedFunction<K, V>(map, compute);
return new MapBasedMemoizedFunction<K, V>(this, map, compute);
}
@NotNull
@Override
public <T> NotNullLazyValue<T> createLazyValue(@NotNull Function0<? extends T> computable) {
return new LockBasedNotNullLazyValue<T>(computable);
return new LockBasedNotNullLazyValue<T>(this, computable);
}
@NotNull
@@ -140,7 +140,7 @@ public class LockBasedStorageManager implements StorageManager {
public <T> NotNullLazyValue<T> createRecursionTolerantLazyValue(
@NotNull Function0<? extends T> computable, @NotNull final T onRecursiveCall
) {
return new LockBasedNotNullLazyValue<T>(computable) {
return new LockBasedNotNullLazyValue<T>(this, computable) {
@NotNull
@Override
protected RecursionDetectedResult<T> recursionDetected(boolean firstTime) {
@@ -156,7 +156,7 @@ public class LockBasedStorageManager implements StorageManager {
final Function1<? super Boolean, ? extends T> onRecursiveCall,
@NotNull final Function1<? super T, Unit> postCompute
) {
return new LockBasedNotNullLazyValue<T>(computable) {
return new LockBasedNotNullLazyValue<T>(this, computable) {
@NotNull
@Override
protected RecursionDetectedResult<T> recursionDetected(boolean firstTime) {
@@ -176,13 +176,13 @@ public class LockBasedStorageManager implements StorageManager {
@NotNull
@Override
public <T> NullableLazyValue<T> createNullableLazyValue(@NotNull Function0<? extends T> computable) {
return new LockBasedLazyValue<T>(computable);
return new LockBasedLazyValue<T>(this, computable);
}
@NotNull
@Override
public <T> NullableLazyValue<T> createRecursionTolerantNullableLazyValue(@NotNull Function0<? extends T> computable, final T onRecursiveCall) {
return new LockBasedLazyValue<T>(computable) {
return new LockBasedLazyValue<T>(this, computable) {
@NotNull
@Override
protected RecursionDetectedResult<T> recursionDetected(boolean firstTime) {
@@ -196,7 +196,7 @@ public class LockBasedStorageManager implements StorageManager {
public <T> NullableLazyValue<T> createNullableLazyValueWithPostCompute(
@NotNull Function0<? extends T> computable, @NotNull final Function1<? super T, Unit> postCompute
) {
return new LockBasedLazyValue<T>(computable) {
return new LockBasedLazyValue<T>(this, computable) {
@Override
protected void postCompute(@Nullable T value) {
postCompute.invoke(value);
@@ -270,14 +270,16 @@ public class LockBasedStorageManager implements StorageManager {
RECURSION_WAS_DETECTED
}
private class LockBasedLazyValue<T> implements NullableLazyValue<T> {
// Being static is memory optimization to prevent capturing outer-class reference at each level of inheritance hierarchy
private static class LockBasedLazyValue<T> implements NullableLazyValue<T> {
private final LockBasedStorageManager storageManager;
private final Function0<? extends T> computable;
@Nullable
private volatile Object value = NotValue.NOT_COMPUTED;
public LockBasedLazyValue(@NotNull Function0<? extends T> computable) {
public LockBasedLazyValue(@NotNull LockBasedStorageManager storageManager, @NotNull Function0<? extends T> computable) {
this.storageManager = storageManager;
this.computable = computable;
}
@@ -296,7 +298,7 @@ public class LockBasedStorageManager implements StorageManager {
Object _value = value;
if (!(_value instanceof NotValue)) return WrappedValues.unescapeThrowable(_value);
lock.lock();
storageManager.lock.lock();
try {
_value = value;
if (!(_value instanceof NotValue)) return WrappedValues.unescapeThrowable(_value);
@@ -328,11 +330,11 @@ public class LockBasedStorageManager implements StorageManager {
// Store only if it's a genuine result, not something thrown through recursionDetected()
value = WrappedValues.escapeThrowable(throwable);
}
throw exceptionHandlingStrategy.handleException(throwable);
throw storageManager.exceptionHandlingStrategy.handleException(throwable);
}
}
finally {
lock.unlock();
storageManager.lock.unlock();
}
}
@@ -342,7 +344,7 @@ public class LockBasedStorageManager implements StorageManager {
*/
@NotNull
protected RecursionDetectedResult<T> recursionDetected(boolean firstTime) {
return recursionDetectedDefault();
return storageManager.recursionDetectedDefault();
}
protected void postCompute(T value) {
@@ -350,10 +352,10 @@ public class LockBasedStorageManager implements StorageManager {
}
}
private class LockBasedNotNullLazyValue<T> extends LockBasedLazyValue<T> implements NotNullLazyValue<T> {
private static class LockBasedNotNullLazyValue<T> extends LockBasedLazyValue<T> implements NotNullLazyValue<T> {
public LockBasedNotNullLazyValue(@NotNull Function0<? extends T> computable) {
super(computable);
public LockBasedNotNullLazyValue(@NotNull LockBasedStorageManager storageManager, @NotNull Function0<? extends T> computable) {
super(storageManager, computable);
}
@Override
@@ -365,11 +367,17 @@ public class LockBasedStorageManager implements StorageManager {
}
}
private class MapBasedMemoizedFunction<K, V> implements MemoizedFunctionToNullable<K, V> {
private static class MapBasedMemoizedFunction<K, V> implements MemoizedFunctionToNullable<K, V> {
private final LockBasedStorageManager storageManager;
private final ConcurrentMap<K, Object> cache;
private final Function1<? super K, ? extends V> compute;
public MapBasedMemoizedFunction(@NotNull ConcurrentMap<K, Object> map, @NotNull Function1<? super K, ? extends V> compute) {
public MapBasedMemoizedFunction(
@NotNull LockBasedStorageManager storageManager,
@NotNull ConcurrentMap<K, Object> map,
@NotNull Function1<? super K, ? extends V> compute
) {
this.storageManager = storageManager;
this.cache = map;
this.compute = compute;
}
@@ -380,7 +388,7 @@ public class LockBasedStorageManager implements StorageManager {
Object value = cache.get(input);
if (value != null && value != NotValue.COMPUTING) return WrappedValues.unescapeExceptionOrNull(value);
lock.lock();
storageManager.lock.lock();
try {
value = cache.get(input);
if (value == NotValue.COMPUTING) {
@@ -406,25 +414,25 @@ public class LockBasedStorageManager implements StorageManager {
return typedValue;
}
catch (Throwable throwable) {
if (throwable == error) throw exceptionHandlingStrategy.handleException(throwable);
if (throwable == error) throw storageManager.exceptionHandlingStrategy.handleException(throwable);
Object oldValue = cache.put(input, WrappedValues.escapeThrowable(throwable));
if (oldValue != NotValue.COMPUTING) {
throw raceCondition(input, oldValue);
}
throw exceptionHandlingStrategy.handleException(throwable);
throw storageManager.exceptionHandlingStrategy.handleException(throwable);
}
}
finally {
lock.unlock();
storageManager.lock.unlock();
}
}
@NotNull
private AssertionError recursionDetected(K input) {
return sanitizeStackTrace(
new AssertionError("Recursion detected on input: " + input + " under " + LockBasedStorageManager.this)
new AssertionError("Recursion detected on input: " + input + " under " + storageManager)
);
}
@@ -432,7 +440,7 @@ public class LockBasedStorageManager implements StorageManager {
private AssertionError raceCondition(K input, Object oldValue) {
return sanitizeStackTrace(
new AssertionError("Race condition detected on input " + input + ". Old value is " + oldValue +
" under " + LockBasedStorageManager.this)
" under " + storageManager)
);
}
@@ -441,22 +449,26 @@ public class LockBasedStorageManager implements StorageManager {
Object value = cache.get(key);
return value != null && value != NotValue.COMPUTING;
}
protected LockBasedStorageManager getStorageManager() {
return storageManager;
}
}
private class MapBasedMemoizedFunctionToNotNull<K, V> extends MapBasedMemoizedFunction<K, V> implements MemoizedFunctionToNotNull<K, V> {
private static class MapBasedMemoizedFunctionToNotNull<K, V> extends MapBasedMemoizedFunction<K, V> implements MemoizedFunctionToNotNull<K, V> {
public MapBasedMemoizedFunctionToNotNull(
@NotNull ConcurrentMap<K, Object> map,
@NotNull LockBasedStorageManager storageManager, @NotNull ConcurrentMap<K, Object> map,
@NotNull Function1<? super K, ? extends V> compute
) {
super(map, compute);
super(storageManager, map, compute);
}
@NotNull
@Override
public V invoke(K input) {
V result = super.invoke(input);
assert result != null : "compute() returned null under " + LockBasedStorageManager.this;
assert result != null : "compute() returned null under " + getStorageManager();
return result;
}
}