Java内存区域与内存溢出异常
- 运行时数据区域
- 程序计数器
- 记录当前线程执行的字节码的行号(指令地址)
- 线程私有
- 唯一一个没有规定任何OutOfMemoryError的区域
- Java虚拟机栈
- 线程私有
- Java方法执行的内存模型:方法执行时,会创建一个栈帧,存储局部变量表、操作数栈、动态链接、方法出口等信息。
- 我们平时说的“栈内存”,是指Java虚拟机栈中的局部变量表。变量局部表存储基本数据类型、对象引用类型。
- 两种异常
- 线程请求的栈深度大于虚拟机所允许的深度,抛出StackOverflowError异常
- 虚拟机栈动态扩展时,无法申请到足够的内存,抛出OutOfMemoryError异常
- 本地方法栈
- 虚拟机栈为虚拟机执行Java方法服务
- 本地方法栈为虚拟机使用到的Native方法服务,作用于虚拟机栈相似
- 抛出StackOverflowError和OutOfMemoryError异常
- Java堆
- 所有线程共享,存放对象实例
- 堆内没有内存完成实例分配,并且堆也无法扩展时,抛出OutOfMemoryError异常
- 方法区
- 所有线程共享
- 存储已被虚拟机加载的类信息、常量、静态变量、即时编译器编译后的代码等数据
- 方法区无法满足内存分配需求时,将抛出OutOfMemoryError异常
- 程序计数器
- OutOfMemoryError异常
- Java堆溢出
- 代码
public class HeapOOM { static class OOMObject { } public static void main(String[] args) { List
list = new ArrayList<>(); while (true) { list.add(new OOMObject()); } }} - 设置虚拟机参数
-Xms20m -Xmx20m -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=C:\Users\xxx\Desktop
- 异常如下
Exception in thread "main" java.lang.OutOfMemoryError: Java heap spaceat java.util.Arrays.copyOf(Arrays.java:3210)at java.util.Arrays.copyOf(Arrays.java:3181)at java.util.ArrayList.grow(ArrayList.java:261)at java.util.ArrayList.ensureExplicitCapacity(ArrayList.java:235)Heap dump file created [28207505 bytes in 0.158 secs]at java.util.ArrayList.ensureCapacityInternal(ArrayList.java:227)at java.util.ArrayList.add(ArrayList.java:458)at HeapOOM.main(HeapOOM.java:15)
- 分析异常
- 将dump下来的堆转储快照文件导入Eclipse Memory Analyzer工具
- 点击Histogram查看类对象占用的空间大小,如下
- 程序通过不断的创建OOMObject对象,导致堆被迅速的占满,从而出现堆内存溢出
- 虚拟机栈和本地方法栈溢出
- 代码
public class JavaVMStackSOF { private int stackLength = 1; public void stackLeak() { stackLength++; stackLeak(); } public static void main(String[] args) { JavaVMStackSOF oom = new JavaVMStackSOF(); try { oom.stackLeak(); } catch (Exception e) { System.out.println("stack length:" + oom.stackLength); e.printStackTrace(); } }}
- 虚拟机参数:
-Xss128k
- 异常如下
Exception in thread "main" java.lang.StackOverflowError at JavaVMStackSOF.stackLeak(JavaVMStackSOF.java:8) at JavaVMStackSOF.stackLeak(JavaVMStackSOF.java:9) at JavaVMStackSOF.stackLeak(JavaVMStackSOF.java:9) at JavaVMStackSOF.stackLeak(JavaVMStackSOF.java:9) at JavaVMStackSOF.stackLeak(JavaVMStackSOF.java:9) at JavaVMStackSOF.stackLeak(JavaVMStackSOF.java:9)........
- 方法区和运行时常量池溢出
- 代码
public class RuntimeConstantPoolOOM { public static void main(String[] args) { List
list = new ArrayList<>(); int i = 0; while (true) { list.add(String.valueOf(i++).intern()); } }} - 虚拟机参数:
-Xms10m -Xmx10m
- 异常如下
Exception in thread "main" java.lang.OutOfMemoryError: Java heap space at java.lang.Integer.toString(Integer.java:403) at java.lang.String.valueOf(String.java:3099) at RuntimeConstantPoolOOM.main(RuntimeConstantPoolOOM.java:12)
- Java堆溢出