import java.io.IOException; import java.util.ArrayList; public class TestOOM { private static final int _8MB = 8 * 1024 * 1024; // -Xms20M -Xmx20M -Xmn10M -XX:+UseSerialGC -XX:+PrintGCDetails -verbose:gc -XX:-ScavengeBeforeFullGC public static void main(String[] args) throws InterruptedException, IOException { new Thread(() -> { ArrayList<byte[]> list = new ArrayList<>(); list.add(new byte[_8MB]); list.add(new byte[_8MB]); }).start(); Thread.sleep(2000); } }
在上述程序中,设置了堆内存为20M,其中新生代区占10M(伊甸园区占8M,from和to平分余下的2M),老年代占10M,结果如下:
子线程连续申请了两个8M的字节数组,导致堆内存溢出,但是主线程依然可以运行,当然肯定会受到堆空间不足的影响。
可以看到老年代中仍存放有子线程第一次申请的8M字节数组,GC并没有因为子线程导致堆内存溢出而回收其占用的堆空间,这是由于Java的垃圾回收机制是依靠可达性算法,而不是线程的生命周期,发生堆溢出时第一次申请的8M字节数组仍然是可达的。