转载

杂记-几个JVM(针对HotSpot)的容易忽视的问题

  • 我们知道,JVM参数配置中 -Xms 表示 JVM 启动时分配的内存、 -Xmx 表示 JVM 运行过程中最大可用内存。
  • 由此可见,随着对象实例增多,超过最大堆分配内存的限制,就会出现OOM。

栈溢出

  • 栈内存容量参数由 -Xss 决定,而栈内存取决于 栈帧数量,即栈深度 ,以及 每个栈帧的大小
  • 虚拟机栈常见的 2 种异常分为 OOM 以及 StackOverflowError ,那么,取决于什么情况,会抛相应的异常呢?

取决于栈内存是否支持扩展,HotSpot虚拟机不支持扩展

  • 由于 HotSpot 虚拟机不支持扩展,因此 OOM 的发生情况:创建线程时就因为无法获得足够内存而出现 OOM ,创建线程时内存不足,恰恰 原因可能是每个线程的栈分配内存设置过大 ,在操作系统内存使用状态的影响下发生。
  • 例如,递归调用导致栈深度过大、定义大量本地变量增加栈帧中本地变量表长度,超过了 -Xss 所决定的栈内存容量,就会抛出 StackOverflowError

方法区和运行时常量池溢出

[小插曲]方法区和常量池的关系?

  • 运行时常量池是方法区的一部分
  • 方法区存储 已被虚拟机加载的类型信息、常量、静态变量 、即时编译器编译后的代码缓存等。
  • 运行时常量池:常量池表,用于存放编译期生成的各种字面量与符号引用。(运行时也可以将新的常量放入池中,例如 String::intern()

[小插曲]方法区 == 永久代?

String::intern()

回归正题

  • 因此,如果使用 String::intern() 来制造方法区和常量池的 OOM

1、JDK6或更早:字符串常量池大小增长,导致永久代的内存大小超过 -XX:MaxPermSize 规定的大小,导致出现 PermGen space 出现 OOM 。 2、JDK7开始,字符串常量池移入Java堆中,使用 String::intern() 报出 OOM 也是 Java heap space

CGLib产生大量的类填充方法区,制造 OOM

  • 1、JDK7出现 PermGen space 出现 OOM
  • 2、JDK8出现 Java heap space

GC Roots指什么?

  • 虚拟机栈中引用的对象,各个线程被调用的方法中使用到的参数、局部变量、临时变量。
  • 方法区类静态属性引用的对象。
  • 方法区常量引用的对象,例如字符串常量池的引用。
  • Java虚拟机内部的引用,Class对象、异常对象、系统类加载器。
  • 同步锁持有的对象(Synchronized)。

参考

  • stackoverflow.com/questions/3…
  • 深入JVM(第三版)
  • russxia.com/2018/02/08/…
原文  https://juejin.im/post/5ea81a77f265da7bbd2f805b
正文到此结束
Loading...