Java虚拟机内存溢出异常--《深入理解Java虚拟机》学习笔记及个人理解(三)
书上P39
1. 堆内存溢出
不断地创建对象, 而且保证创建的这些对象不会被回收即可(让GC Root可达).
/** * 堆内存溢出demo * VM Options: -Xms6m -Xmx6m */ public class HeapOOM { static class OOMObejct { } public static void main(String[] args) { List<OOMObejct> list = new ArrayList<>(); while (true) { list.add(new OOMObejct()); } } }
会内存溢出, 输出结果如下:
如果是用下面这段代码的话, 是不会内存溢出的. 因为有GC. 每次new 的 Object在下次for循环中都退出了作用域, 虚拟机栈不再持有对象的引用. 所以会被GC掉. 不会溢出.
/** * 堆内存溢出demo * VM Options: -Xms6m -Xmx6m */ public class HeapOOM { static class OOMObejct { } public static void main(String[] args) { while (true) { new OOMObejct(); } } }
visualVM的堆内存图如下:
2. 虚拟机栈溢出
/** * 栈内存溢出demo * VM Options: -Xms6m -Xmx6m */ public class StackOverflow { private int stackDepth; private void stackLeak() { stackDepth++; stackLeak(); } public static void main(String[] args) { StackOverflow oom = new StackOverflow(); try { oom.stackLeak(); } catch (Throwable e) { System.out.println(oom.stackDepth); System.err.println(e.toString()); } } }
输出结果如下(下面部分结果可能根据机器环境不同而不同):
3. 创建线程导致的内存溢出
import java.util.concurrent.atomic.AtomicInteger; /** * 创建线程导致的内存溢出demo * VM Options: -Xms6m -Xmx6m */ public class CreateThreadOOM { static AtomicInteger counter = new AtomicInteger(0); public static void main(String[] args) { while (true) { new Thread(() -> { try { System.out.println(counter.incrementAndGet()); Thread.sleep(Integer.MAX_VALUE); } catch (InterruptedException e) { e.printStackTrace(); } }).start(); } } }
输出结果如下(下面部分结果可能根据机器环境不同而不同):
4. 直接内存溢出
这段代码我这里没有运行出书上的效果...
书上的意思应该是, 设定了直接内存大小最大为10M后, 继续申请的话, 就会报异常..
在我电脑上, 虽然也设置了MaxDirectMemorySize=10m , 但是这玩意硬生生地申请了10G的虚拟内存也没停下, 最后被操作系统强制停止了.....(运行了几次电脑都快没电了)
import sun.misc.Unsafe; import java.lang.reflect.Field; /** * VM Options: -Xms6m -Xmx6m -XX:MaxDirectMemorySize=10m */ public class DirectMemoryOOM { private static final int _1MB = 1024 * 1014; public static void main(String[] args) throws IllegalAccessException, InterruptedException { Field unsafeFile = Unsafe.class.getDeclaredFields()[0]; unsafeFile.setAccessible(true); Unsafe unsafe = (Unsafe) unsafeFile.get(null); while (true) { unsafe.allocateMemory(_1MB); Thread.sleep(10); } } }