Of course, this is implementation dependent behavior. HotSpot has some heap of memory inaccessible to regular allocations, the JVM can use to build OutOfMemoryError in. However, since Java allows an arbitrary number of threads, an arbitrary number of threads can hit the wall at the same time, so there is no guarantee that there is enough memory to create a separate OutOfMemoryError instance for each of them.
Therefore, when starting a JVM that persists for the duration of the session, a crash instance of OutOfMemoryError is created to ensure that the error can be selected even if there is actually no memory. Since the instance will be used for all threads that encounter an error while there is actually no memory, you will recognize this extraneous condition because this error will not contain a stack trace.
Next 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'); });
works under jdk1.8.0_65 with -Xmx100M and wait 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 can serve as a construct for four different OutOfMemoryError instances (including the memory needed to record their stack traces), while all other threads should return to the reserved shared instance.
Of course, numbers can vary in different environments.