在Java中创建的OutOfMemoryError对象在哪里

man*_*osh 5 java jvm memory-management exception-handling jvm-hotspot

OutOfMemoryError当堆没有足够的内存来创建新对象时,就会发生这种情况.如果堆没有足够的内存,则OutOfMemoryError创建对象的位置.我想了解这一点,请指教.

Hol*_*ger 7

当然,这是一种依赖于实现的行为.HotSpot有一些堆内存对于普通分配是不可访问的,JVM可以用来构造一个OutOfMemoryError.但是,由于Java允许任意数量的线程,因此任意数量的线程可能同时碰壁,所以没有保证内存足以OutOfMemoryError为每个实例构建一个独特的实例.

因此,OutOfMemoryError在整个会话期间持续存在的JVM启动时创建紧急实例,以确保即使实际上没有剩余内存也可以抛出错误.由于实例将为遇到错误的所有线程共享,而实际上没有剩余内存,因此您将通过此错误将没有堆栈跟踪这一事实识别出这种无关的条件.

以下程序

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');
});
Run Code Online (Sandbox Code Playgroud)

跑了下来jdk1.8.0_65,-Xmx100M等了半分钟给了我

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
Run Code Online (Sandbox Code Playgroud)

显示保留的内存可以用于构造四个不同的OutOfMemoryError实例(包括记录其堆栈跟踪所需的内存),而所有其他线程必须回退到保留的共享实例.

当然,数字可能因不同环境而异.


Kay*_*man 5

它由 JVM 本地生成,不受 -Xmx 或其他参数的限制。为您的程序保留的堆已用尽,而不是 JVM 可用的内存。