Of course, this is an implementation-dependent behavior. HotSpot has some heap memory inaccessible for ordinary allocations, the JVM can use to construct an OutOfMemoryError
in. However, since Java allows an arbitrary number of threads, an arbitrary number of threads may hit the wall at the same time, so there is no guaranty that the memory is enough for constructing a distinct OutOfMemoryError
instance for each of them.
Therefore, an emergency OutOfMemoryError
instance is created at the JVM startup persisting throughout the entire session, to ensure, that the error can be thrown even if there is really no memory left. Since the instance will be shared for all threads encountering the error while there’s really no memory left, you will recognize this extraneous condition by the fact that this error will have no stack trace then.
The following program
ConcurrentHashMap<OutOfMemoryError,Integer> instances = new ConcurrentHashMap<>();
ExecutorService executor = Executors.newCachedThreadPool();
executor.invokeAll(Collections.nCopies(1000, () -> {
ArrayList<Object> list = new ArrayList<>();
for(;;) try {
list.add(new int[10_000_000]);
} catch(OutOfMemoryError err) {
instances.merge(err, 1, Integer::sum);
return err;
}
}));
executor.shutdown();
System.out.println(instances.size()+" distinct errors created");
instances.forEach((err,count) -> {
StackTraceElement[] trace = err.getStackTrace();
System.out.println(err.getClass().getName()+"@"+Integer.toHexString(err.hashCode())
+(trace!=null&&trace.length!=0? " has": " has no")+" stacktrace, used "+count+'x');
});
running under jdk1.8.0_65
with -Xmx100M
and waiting half a minute gave me
5 distinct errors created
java.lang.OutOfMemoryError@c447d22 has no stacktrace, used 996x
java.lang.OutOfMemoryError@fe0b0b7 has stacktrace, used 1x
java.lang.OutOfMemoryError@1e264651 has stacktrace, used 1x
java.lang.OutOfMemoryError@56eccd20 has stacktrace, used 1x
java.lang.OutOfMemoryError@70ab58d7 has stacktrace, used 1x
showing that the reserved memory could serve the construction of four distinct OutOfMemoryError
instances (including the memory needed to record their stack traces) while all other threads had to fall back to the reserved shared instance.
Of course, numbers may vary between different environments.
与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…