【读书笔记】深入理解Java虚拟机

一 JVM 组成

在这里插入图片描述

  1. 程序计数器:当前线程执行的字节码行号指示器(唯一一个在Java虚拟机规范中不会出现OOM的区域)
  2. 虚拟机栈:
    • 线程私有,生命周期与线程相同
    • 虚拟机栈描述的是Java方法执行的内存模型: 每个方法在执行的同时都会创建一个栈帧( Stack Frame[1]) 用于存储局部变量表、 操作数栈、 动态链接、 方法出口等信息。 每一个方法从调用直至执行完成的过程, 就对应着一个栈帧在虚拟机栈中入栈到出栈的过程;
    • 两种异常:1️⃣线程请求栈深度大于虚拟机允许深度 -> StackOverFlow 2️⃣虚拟机栈动态拓展时无法申请到足够内存 -> OOM
  3. 本地方法栈:Native服务,可能出现的异常与虚拟机栈相同
  4. 堆:对象空间
  5. 方法区:
    • 也称为“非堆”, “永久代”
    • 线程共享,存储JVM加载的类信息,常量,静态变量,及时编译器编译后的代码;
    • 可能异常:OOM(方法区无法满足内存分配需求)
  6. 运行时常量池:方法区的一部分,存放编译器生产的符号引用
  7. 直接内存:由于NIO可以使用Native函数库分配堆外内存,设置-Xmx需注意分配此部分大小

二 对象的创建

对象内存布局or组成(三部分)

  1. 对象头
    (哈希码( HashCode) 、 GC分代年龄、 锁状态标志、 线程持有的锁、 偏向线程ID、 偏向时间戳等)
  2. 实例数据
  3. 对齐填充(对象大小必须为8字节的整数倍)

对象已死?

  • 引用计数法:存在循环依赖问题,不彻底
  • 可达性分析算法

哪些可以作为GC Roots的对象:
1 虚拟机栈( 栈帧中的本地变量表) 中引用的对象
2 方法区中类静态属性引用的对象
3 方法区中常量引用的对象
4 本地方法栈中JNI( 即一般说的Native方法) 引用的对象
在这里插入图片描述

再谈引用?强软弱虚引用分类

三 GC算法

①标记-清除法

GC过程(标记 + 清除 2个过程) + 不足点(效率低 + 内存碎片)
在这里插入图片描述

②复制算法

空间均分为两块,空间利用率低;
大多数对象存活时间短,鉴于此HotSpot默认设置Eden:Survivor = 8:1
在这里插入图片描述

③标记-整理算法

在这里插入图片描述

④分代收集算法

新生代 + 老年代 的组合
新生代利用复制算法,老年代利用“标记-清除”or“标记-整理”算法回收

四 垃圾收集器

分类:
在这里插入图片描述

①Serial串行收集器

  • 单线程
  • 垃圾回收时 - STW机制
    在这里插入图片描述

②parNew收集器

  • ①的多线程版本
    在这里插入图片描述

③parallel Scavenge收集器

  • CMS等收集器的关注点是尽可能地缩短垃圾收集时用户线程的停顿时间, 而Parallel Scavenge收集器的目标则是达到一个可控制的吞吐量( Throughput)
  • 可设置参数:最大GC停顿时间 -XX: MaxGCPauseMillis; 吞吐量大小 -XX:GCTimeRatio

④Seral Old收集器

在这里插入图片描述

⑤Parallel Old收集器

在这里插入图片描述

⑥CMS收集器

  • 以获取最短回收停顿时间为目标
  • 优点:并发收集,低停顿
  • 缺点:
    ++ 对CU资源敏感
    ++ 无法处理浮动垃圾
    ++ 基于“标记-清除”算法,碎片多
    在这里插入图片描述

初始标记( CMS initial mark)

STW,仅标记GC Roots能关联到的对象,速度快

并发标记( CMS concurrent mark)

STW,进行GC RootsTracing过程

重新标记( CMS remark)

修正并发标记期间因为用户程序继续运作而导致标记产生变动的那一部分对象的标记记录,停顿时间比初始标记长,比并发标记短

并发清除( CMS concurrent sweep)

执行GC过程

综上,耗时最长的并发标记和并发清除过程收集器线程能与用户线程一起工作!

⑦G1收集器

  • 空间整合:G1从整体来看是基于“标记—整理”算法实现的收集器, 从局部( 两个Region之间) 上来看是基于“复制”算法实现的
  • 可预测停顿:将整体空间分块划分维护
    在这里插入图片描述

初始标记( Initial Marking)

标记GC Roots关联对象

并发标记( Concurrent Marking)

从GC Root开始对堆中对象进行可达性分析, 找出存活的对象, 这阶段耗时较长, 但可与用户程序并发执行

最终标记( Final Marking)

最终标记阶段则是为了修正在并发标记期间因用户程序继续运作而导致标记产生变动的那一部分标记记录, 虚拟机将这段时间对象变化记录在线程Remembered Set Logs里面, 最终标记阶段需要把Remembered Set Logs的数据合并到Remembered Set中, 这阶段需要停顿线程, 但是可并行执行

筛选回收( Live Data Counting and Evacuation)

首先对各个Region的回收价值和成本进行排序,根据用户所期望的GC停顿时间来制定回收计划,可以并行也可以短暂停顿提升GC效率

垃圾收集器参数总结

在这里插入图片描述在这里插入图片描述

五 性能监控工具与故障处理工具

①jdk命令行

jps jstat jinfo jmap jhat jstack

②可视化工具

jConsole VisualVM

六 典型场景下实战调优

Loading … …

七 类加载机制

类加载机制:虚拟机把描述类的数据从Class文件加载到内存, 并对数据进行校验、 转换解析和初始化, 最终形成可以被虚拟机直接使用的Java类型, 这就是虚拟机的类加载机制;

Class文件是一组以8字节为基础单位的二进制流
在这里插入图片描述

①加载

加载阶段的过程:
1) 通过一个类的全限定名来获取定义此类的二进制字节流
2) 将这个字节流所代表的静态存储结构转化为方法区的运行时数据结构
3) 在内存中生成一个代表这个类的java.lang.Class对象, 作为方法区这个类的各种数据的访问入口

②验证

  • 确保Class文件的字节流中包含信息符号JVM要求
  • 总体上有以下验证过程
    1. 文件格式验证:固定魔数开头、版本号支持
    2. 元数据验证:父类继承关系、抽象类
    3. 字节码验证:数据流和控制流分析确保合理,类方法体校验分析确保安全
    4. 符号引用验证:对类自身以外信息匹配性校验

③准备

正式为类变量分配内存并设置类变量初始值的阶段, 这些变量所使用的内存都将在方法区中进行分配

④解析

常量池内符号引用替换为直接引用的过程

⑤初始化

八 类加载器

双亲委派模型

**过程:**如果一个类加载器收到了类加载的请求, 它首先不会自己去尝试加载这个类, 而是把这个请求委派给父类加载器去完成, 每一个层次的类加载器都是如此, 因此所有的加载请求最终都应该传送到顶层的启动类加载器中, 只有当父加载器反馈自己无法完成这个加载请求( 它的搜索范围中没有找到所需的类) 时, 子加载器才会尝试自己去加载
在这里插入图片描述

如何破坏双亲委派模型?

重写类加载器


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Wimb

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值