深入了解java虚拟机-读书笔记

时间:2021-11-11 14:18:50
     JAVA 虚拟机

概念:
1 . java虚拟机一般表示下三种情形:
1. 抽象规范
2. 一个具体的实现
3. 一个运行中的虚拟机实例(一个java程序启动一个虚拟机实例)
2.java的64位虚拟征途
面临指针膨胀数据类型补白等问题,整体较32位性能差距15%左右
3.java语法的一次重要扩充
java1.5扩充:自动装箱、泛型、自动注解、枚举、可变参数、遍历循环等语法;
知识点:
1.JVM 知识点
java虚拟机的模块分布图
加载器===>运行内存===>外部接口
深入了解java虚拟机-读书笔记

(1)PCR 程序计数器
字节码行号指示器(方便执行引擎取下一条指令),线程私有内存;如果执行的是字节码计数器值为字节码地址,native方法值为unfind;唯一一个不会出现OutofMemoryError异常的内存区域

(2)VM Stack 虚拟机栈
线程私有内存,java方法执行的模型,每个方法执行都会创建一个栈针(stack frame),每个方法从调用到返回对应一个栈针从虚拟机栈的入栈到出栈的过程。
其中double和float类型占两个局部变量空间(slot);returnAddress指一条字节码指令的地址;
异常:如果线程请求的栈深度大于虚拟机栈允许的深度会抛出*Error ,不能扩展虚拟机栈时抛出OutMemoryError

如下图
深入了解java虚拟机-读书笔记
(3)native method stack 本地方法栈
与 Vm stack 是功能等价,区别是本地方法栈是提供给虚拟机自己的执行方法的服务
(4)heap java的堆
1.所有线程共享内存,虚拟机启动时创建,唯一目的存放对象实例和数组,
2.是垃圾回收的主要区域又称GC堆,细化为
[图片]深入了解java虚拟机-读书笔记
3.实现只要求逻辑连接就ok,可扩展通过-xms 和-xmx 不能扩展会抛出outofMemoryError异常
(5)method area 方法区 (包含常量池)
1.线程共享区域
2.作用: 存放虚拟机加载的类信息、常量池、静态变量、即时编译后的代码
3.别名: Non-heap(非堆)本质是堆的逻辑部分,按代划分又称永久代
4.GC会针对常量池和类型的回收,也会抛出outofMemoryError异常
5.运行时常量区:方法区的一部分存放 字面量和符号引用
(6)Direct Memory 直接内存
是虚拟机运行内存的一部分,如NIO就是使用这里内存,不可以忽略内存大小,保证各个区域内存总和小于物理内存的大小;也会抛出outofMemoryError异常;
这部分不像其他不足会GC,它只有老年代满了然后FULL GC时顺便回收它

2.快速定位内存溢出异常
案例1:模拟java堆溢出场景重现:
创建对象达到堆最大容量时会扩展(初始值-xms 与 最大值-xmx 设置为一样大即无法扩展)
-XX:+HeapDumpOnOutOfMemoryError:获取快照
-Xms 设置堆初始值
-Xmx 设置堆最大值
代码:
public class Test
{
//——function main—————————
List list = new LinkedList();
while(true)
{
list.add(new Test());
}
//———————————————–
}
编译—>运行:
java -Xms20m -Xmx20m -XX:+HeapDumpOnOutOfMemoryError Test
结果:
java.lang.OutOfMemoryError: Java heap space
Dumping heap to java_pid32360.hprof …
Heap dump file created [31096198 bytes in 0.697 secs]

案例2:模拟栈溢出场景(虚拟机栈和本地方法栈)
-Xss 虚拟机栈设置
-Xoss 本地方法栈(hotspot 不区分虚拟机栈和本地方法栈此参数无效)
抛出异常条件:
StackOutOfMemoryError: 请求的栈深度大于最大深度
OutOfMemoryError: 请求扩展栈无法申请到

代码:
public class Test
{
public void stackError()
{
stackError();
}
//——function main—————————
Test t = new Test();
t.stackError();
//———————————————–
}

运行:
java -Xss128k Test
结果:
Exception in thread “main” java.lang.*Error
处理方案:

案例3:模拟方法区场景(运行时常量池属于方法区两者一块)
-XX:PermSize 永久代的初始值
-XX:MaxPermSize 永久代的最大值
抛出异常条件:
OutOfMemoryError: 运行时常量池溢出导致异常
jdk1.6及之前版本会出现1.7后
代码:
public class Test
{
//——function main—————————
List list = new LinkedList();
int i = 100;
while(true)
{
list.add(String.valueOf(i++).intern());
}
//———————————————–
}

运行:
java -XX:PermSize=10m -XX:MaxPermSize=10m Test
结果:
java.lang.OutOfMemoryError: PermGen space

总结: 常量池在方法区jdk1.7后逐渐去掉String改为引用,值放在堆中

案例4:模拟直接内存溢出场景
-XX:MaxDirectMemorySize 直接内存最大值
抛出异常条件:
OutOfMemoryError: 运行时常量池溢出导致异常
代码:
略。。。

运行:
java -Xmx10m -XX:MaxDirectMemorySize =10m Test
结果:
Exception in thread “main” java.lang.OutOfMemoryError
处理方案:
此异常可以通过观察heap dump ,dump文件很小而且程序中直接或间接使用过NIO,建议检查此种情况。加大直接内存的容量