If ClassValueMap.removeEntry gets something like OutOfMemoryError here:
// In an initialized state. Bump forward, and de-initialize.
classValue.bumpVersion();
then the ClassValue is permanently broken. Future calls to remove() will do nothing, and computeValue will never be called again. Instead, the value will be supplied from the cache.
% cat CV.java
import java.util.ArrayList;
import java.util.List;
public class CV {
static int version = 0;
static final ClassValue<String> resolvedJavaType = new ClassValue<>() {
@Override
protected String computeValue(Class<?> type) {
return type.getName() + (++version);
}
};
static void eatMemory(List<Object> list) {
int size = 1000000;
while (true) {
try {
list.add(new Object[size]);
} catch (OutOfMemoryError oom) {
size /= 2;
if (size == 0) {
return;
}
}
}
}
public static void main(String[] args) {
var v1 = resolvedJavaType.get(CV.class);
List<Object> storage = new ArrayList<Object>();
boolean done = false;
while (!done) {
eatMemory(storage);
try {
resolvedJavaType.remove(CV.class);
} catch (Throwable t) {
done = true;
storage = null;
}
}
resolvedJavaType.remove(CV.class);
var v2 = resolvedJavaType.get(CV.class);
System.err.println("v1 " + v1);
System.err.println("v2 " + v2);
System.err.println("max version " + version);
if (version != 2 || v1 == v2) {
throw new RuntimeException("Failed");
}
}
}
% javac CV.java
% java -Xmx64m CV
v1 CV1
v2 CV1
max version 1
Exception in thread "main" java.lang.RuntimeException: Failed
at CV.main(CV.java:47)