1. JVM运行时内存 图
程序计数器
当前线程执行的字节码的行号指示器,线程通过这部分来选择下一条指令,通过这个部分来实现分支,循环等操作。没有OOM,没有参数可以控制
Java虚拟机栈
描述方法执行的内存区,一个方法的执行就是形成一个栈帧入栈和出栈的过程
栈帧(局部变量表,操作数栈, 动态链接), 局部变量表就是参数和一些方法内的局部变量,操作数栈是方法中的一些操作的运算用的字节码, 动态链接是区别于静态链接的部分,主要包含一些执行信息和资源
包含了两种异常: 线程请求的栈深度大于虚拟机所允许的深度,将抛出StackOverflowError异常。
虚拟机栈扩展是无法申请到足够的内存时抛出OutOfMemoryError异常
-Xss 设置一个线程中栈帧的大小总和
-Xss 参数设置 一个线程中栈帧的大小总和
本地方法栈
跟Java虚拟机栈功能类似,HotSpot中是合并了的
Java堆
GC堆,使用分代收集的算法。 会抛出OOM异常,用-Xmx(最大堆大小) -Xms(初始堆大小)
方法区
存储加载的类信息、常量、静态变量、即时编译器编译后的代码(也就是机器码)。
HotSpot中可能会被称为永久带,但是实际上很多的JVM实现中是没有永久带这个概念的,HotSpot也在计划取消这个定义
GC操作基本上只有常量池的回收和类型卸载
运行时常量池
在Class文件中保存的字面量以及符号引用和符号引用解释之后的直接引用放在这里。
运行时常量可以动态的进行添加,典型的用法是String的intern方法,能够看常量池中是否存在,存在则返回这个常量的引用,不存在则创建一个。
2. 各种内存溢出
2.1 堆溢出
设置JVM对内存为比较小。
然后不停的new对象。
-Xms10m -Xmx10m
public class HeapOom { public static void main(String[] args) { List<OomObject> ooms = new ArrayList<OomObject>(); while (true) { ooms.add(new OomObject()); } } } class OomObject{}输出:
Exception in thread "main" java.lang.OutOfMemoryError: Java heap space
2.2 Java虚拟机站溢出
-Xss 设置每个线程的堆栈大小,越大则能够支持越多层的方法调用。
深度超出的可以使用-Xss设置较小的值,然后使用无跳出方法递归调用来做到
public class StackSOF { private int stackLength = 1; public void stackLeak(){ stackLength ++; stackLeak(); } public static void main(String[] args) { StackSOF ss = new StackSOF(); try { ss.stackLeak(); } catch (Throwable t) { System.out.println("栈深度为:" + ss.stackLength); t.printStackTrace(); } } }输出:
栈深度为:913 java.lang.StackOverflowError
无法申请到足够的空间,可以用-Xss加到每个线程的栈帧大小。 然后创建多个线程,直到内存溢出。
public class StackOOM { public static void main(String[] args) { while (true) { Thread thread = new Thread(new Runnable() { @Override public void run() { while(true){} } }); thread.start(); } } }
因为Java的线程会映射到Windows内存线程上,因此有可能造成系统假死。另外把-Xss设置的越大,就越会溢出,因为系统物理内存减去JVM的内存再除以Xss才是能创建的线程个数。
2.3 运行时常量溢出
使用-XX:PermSize和-XX:MaxPermSize限制方法区大小
参数
-XX:PermSize=1m -XX:MaxPermSize=2m
代码
public class RuntimeConstPoolOOM { public static void main(String[] args) { List<String> list = new ArrayList<String>(); int i = 0; while (true) { list.add(String.valueOf(i++).intern()); } } }
输出
Exception in thread "main" java.lang.OutOfMemoryError: PermGen space
2.4 方法区溢出, 加载很多类,或者是使用动态字节码技术等