美文网首页
JVM-理论

JVM-理论

作者: 西海岸虎皮猫大人 | 来源:发表于2020-10-22 12:29 被阅读0次

1 概述

java 8使用比例最高,非java 8直接装java 11即可
字节码可以由多种语言提供,jvm不止可以解释java程序
java不是最强大的语言,但jvm是最强大的虚拟机
3大难题: cpu os 编译器
jvm使多语言混合编程成为可能
java语言由jcp组织管理
3大虚拟机: hotspot jrockit j9
jdk11 革命性的zgc
android 5.0之前使用dalvik虚拟机
早期classic vm只提供解释器,逐行解释,循环代码也需要逐行,效率低

参考资料

官方规范
Java虚拟机规范(官方文档中文翻译)
深入理解Java虚拟机
自己动手写Java虚拟机

jvm架构
jvm整体结构

多个线程共享方法区和堆
执行引擎包括解释器\即时编译器和垃圾回收器
JIT编译器可以对热点代码编译成机器指令并缓存,提高程序性能
只用JIT会导致暂停时间过长
hotspot是基于栈的指令集架构,基于栈设计实现更简单且不需硬件支持可移植性好,基于寄存器更高效但依赖硬件
基于栈指令集小,指令多

jvm生命周期

启动: 引导类加载器加载初始类
执行: 执行java程序的是jvm进程
退出: 正常异常退出 | 操作系统错误 | 调用system或runtime的exit方法

hotspot vm

热点探测: 通过计数器找到热点代码,触发即时编译或栈上替换
编译器解释器协同,平衡响应时间与执行性能
对象可以在栈上分配

jrockit vm

主要针对服务器端,不太关注启动速度,不包含解释器,全部即时编译器
最快的jvm
mission control套件,监控生产环境(内存泄露)

j9 vm

定位与hotspot接近
用于ibm产品
开源openj9

taobao jvm

基于openjdk
声明周期长的对象移到堆外
多个vm共享对象

dalvik

5.0后替换为art vm
基于寄存器架构

2 类加载机制

类加载子系统
类加载器

从文件系统或网络加载class文件
只负责类的加载,是否可运行由执行引擎决定
加载的类信息存放于方法区,方法区还存放运行时常量池

类加载过程

加载 -> 链接 -> 初始化
加载:

  • 获取二进制字节流
  • 转化为方法区的运行时数据结构
  • 内存中生成Class对象
    运行时计算生成(动态代理)
    从加密文件获取

2 垃圾回收算法

本地方法栈和虚拟机栈无gc,有内存溢出
内存泄露: 对象无法被回收
哪些需要回收: 标记阶段
如何回收: 清除阶段
标记阶段:

  • 引用计数算法
  • 可达性分析算法
    清除阶段:
  • 标记-清除算法
  • 复制算法
  • 标记压缩算法
    分代收集算法
    增量收集算法
引用阶段算法

针对堆空间
对象不被引用宣判死亡
优点: 实现简单,效率高
缺点:

  • 需要单独字段存储计数器,增加存储空间开销
  • 每次赋值更新计数器,伴随加法减法操作,增加时间开销
  • 无法处理循环引用问题
可达性分析算法

解决循环引用问题,防止内存泄露
根对象是一组必须存活的引用
gc roots:

  • 栈中引用的对象
  • 本地方法栈引用的对象
  • 静态属性引用的对象
  • 常量引用的对象
  • 同步锁引用的对象
  • 虚拟机内部引用
    可达性分析必须在一个一致性的快照中进行,导致STW
    CMS枚举根节点也会停顿
对象finalization机制

回收前调用finalize()方法,在Object类中
用于对象回收时资源释放,关闭文件 socket 数据库连接
不要主动调用finalize()

对象三种状态

可触及 可复活 不可触及
如果对象不可达,finalize()方法调用前为可复活状态

MAT

堆内存分析器,查看内存泄露和内存消耗
性能分析工具
基于eclipse开发
获取dump文件 jmap

JProfiler
  • gc溯源
    开发中往往查看某个引用变量支上的gc root
    live memory
  • oom
    生成堆空间oom dump文件,profiler打开
标记 - 清除算法

堆内存耗尽stw
清除是把对象地址放到空闲列表中,并不是真正的置空
标记: 从根节点遍历,header标记被引用对象
清除: 对堆线性遍历,回收header中无标记变量
缺点:
效率低
gc stw
内存碎片,需要维护空闲列表

复制算法

对象地址变化,引用也要变
为了解决标记-清除算法效率缺陷
内存分两块,复制可达对象到连续区域
适用于新生代,s0 s1即为复制算法
优点:
无标记清除过程,效率高
内存连续
缺点:
需要2倍内存空间
对于g1这种分拆成大量region的gc,内存占用和时间开销大
特别:
垃圾对象多且大的问题

标记 - 压缩算法

在标记清除算法基础上进行内存碎片整理
适用于老年代,解决标记 - 清除算法效率问题
一阶段标记,二阶段压缩到内存一侧

分代收集算法

算法各有优势,不同周期不同算法

  • 新生代
    复制算法,1/10空闲
  • 老年代
    混合标记清除和标记压缩
    mark阶段开销与存活对象数量正比
    sweep阶段与管理区域大小正比
CMS

标记清除算法,效率高
随便问题使用searial old gc(标记压缩算法)

3 垃圾回收器

分类

按线程分串行和并行
按工作模式分独占式和并发式,并发式用户线程和gc线程并发
按碎片处理方式分压缩式和非压缩式
按工作内存空间分年轻代和老年代

性能指标评估
  • 吞吐量
    用户时间占总时间比例
  • 暂停时间
    stw时间
  • 内存占用
    java堆占内存大小
    三者构成不可能三角,暂停时间重要性日益凸显
    重点关注吞吐量和暂停时间
串行回收器
  • serial收集器
    hotspot client模式默认新生代收集器
    复制算法 串行回收 stw
  • searial old收集器
    client模式默认,使用标记-压缩算法
    server模式两个用途,与新生代Parallel Scavenge配合,作为老年代cms的后备方案
# 新生代老年代都使用串行收集器
-XX: +UseSerialGC
ParNew

新生代
并行回收,searial的多线程版本
年轻代复制算法 stw机制
server模式新生代默认gc
新生代parnew,老年代可以cms或serial old
jdk新版本移除cms和serial old
新生代回收频繁,并行高效
4核心可以开4线程
除searial,只有parnew可以配合cms

-XX:+UseParNewGC
# 线程数不要超过CPU个数
-XX:UseParNewGCThreads
Parallel回收器

parallel scavenge同parnew, 复制算法 并行回收 stw
吞吐量可控,自适应调节策略
高吞吐量适合后台运行不需太多交互,如订单处理\科学计算等
parallel old 老年代收集器,标记压缩
jdk8默认parallel scavenge和parallel old

CMS

老年代
低延迟,强交互
hotspot真正意义的并发收集器
cms不能配合parallel,searial和parnew 2选一

  • cms工作原理
    初始标记(stw) -> 并发标记 - 重标记(stw) -> 并发清理
    初始标记: 仅标记gc root能直接关联的对象
    并发标记: 遍历对象图,耗时长
    重新标记: 修正并发变动
    并发清除: 不移动对象,可与用户线程并发
G1

分代式区域化
适应不断扩大的内存和处理器数量,降低延迟兼顾吞吐
目标: 延迟可控尽可能高吞吐
全功能收集器
并行会后,堆分为region,避免在全区域垃圾回收
跟踪各region垃圾回收价值
jdk 9之后的默认收集器,取代了cms及parallel + parallel的组合
优势:

  • 并行与并发
  • 分代收集
    不要求eden区 年轻代 老年代连续,也不固定大小和数量
    堆分region,从逻辑上包含年轻代和老年代
    g1同时兼顾新生 老年代
  • 空间整合
    cms若干次gc后进行碎片整理
    g1 region之间是复制算法,整体上市标记压缩算法,内存回收以region为单位
    利于长时间运行
    堆大g1优势明显
  • 可预测的停顿时间模型
    回收部分region,优先回收价值大的region
    g1未必比cms延时停顿最好情况好,但比最差情况差
    缺点:
    对cms不具备压倒优势,垃圾收集内存占用和执行负载较高
    小内存应用cms表现优,g1大规模应用具备优势
    region:
    region大小相同,jvm运行期不变
    新生代 老年代不要求物理隔离,不要求连续
    eden去 suivivior区(不分s1 s0) old humongous
    单个region只能属于一个角色
    humongous主要用于存储大对象,超过1.5个region使用H
    堆中大对象放到老年代如果短期存在对gc造成影响,连续H区找不到则启动full gc
    region内存分配使用指针碰撞
#  指定使用g1
-XX: +UseG1GC 
# region大小,2的幂,目标是划分为2048个区域
-XX: +G1HeapRegionSize 
# GC停顿目标,不保证100%,默认20ms
-XX: MaxGCPauseMillis
# stw工作线程数
-XX: ParallelGCThreads
# 并发标记线程数,设为上面的1/4左右
-XX: ConcGCThreads
# 堆占用率阈值,超过触发gc,默认45
-XX: InitiatingHeapOccupanyPercent

适用场景:
服务端大内存多处理器
如: 6GB或更大,可预测暂停时间小于0.5s
g1可以使用应用线程加速gc
回收过程:
年轻代gc 老年代并发标记 混合回收 (单线程独占式高强度full gc, 失败保护机制)
eden区用尽时,并行独占式收集,年轻代移动到s区或old区
堆内存超过45%开始老年代并发标记
标记完成开始混合回收

记忆集 - Remember Set:
一个对象被不同region引用的问题,一个region的对象可能被其他region引用
如果回收新生代扫描老年代会降低minor gc效率
解决 ->
记忆集记录哪些区域引用了当前region的对象
每次引用类型写数据产生写屏障暂时中断操作,并检查引用指向的对象是否和引用在不同region,如果不同则记录到记忆集
优化建议:
避免显示设置年轻代大小
暂停时间不要过于严苛,会导致更高频的gc
g1吞吐量目标是10%的gc时间

zgc

https://docs.oracle.com/en/java/javase/12/gctuning/
jdk14新特性
参考:
<深入理解Java虚拟机>
<新一代垃圾回收器 ZGC设计与实现>
革命性
目标:对吞吐影响不大限制gc停顿到10ms
并发标记->并发预备重分配->并发重分配->并发重映射
初始标记stw

gc总结
垃圾收集器对比图

serial -> parallel -> cms -> g1 -> zgc


搭配

现在的互联网项目基本都是g1

gc日志分析

# 打印gc日志
# 原因 时间
-XX: +PrintGC
# 打印gc详情日志
# Metaspace 1.8后方法区叫做元空间
-XX: +PrintGCDetails
# 时间戳
-XX: +PrintGCTimeStamps
# 日期时间戳
-XX: +PrintGCDateStamps
# 日志输出路径
-Xloggc: ../logs/gc.log
新生代gc log说明

jdk8大对象直接进入老年代

日志分析工具

gcviewer gceasy(建议)

新发展

epsilon gc
no-op,只做内存分配
shenandoah gc
redhat主导,暂停时间与堆大小无关

相关文章

  • JVM-理论

    1 概述 java 8使用比例最高,非java 8直接装java 11即可字节码可以由多种语言提供,jvm不止可以...

  • JVM类加载器与双亲委派模型(JDK8)

    引言 在上文JVM-类加载机制[https://imchenway.com/2021/07/01/JVM-%E7%...

  • JVM-常见参数

    [TOC] JVM-常见参数 实验平台MacOSmacOS Catalina 10.15内存 8 GB 2133 ...

  • Java编程技术之浅析JVM内存

    JVM JVM->Java Virtual Machine:Java虚拟机,是一种用于计算设备的规范,它是一个虚构...

  • JVM-引用

      Java引用类结构如下所示:   强引用:就算出现OOM也不对该对象进行回收,不进行GC。   软引用:系统内...

  • JVM-对象

    这里研究的是普通 java 对象,不包括数组和 Class 对象等。 1. 对象的创建 1.1. new 我们创建...

  • JVM-从字节码到运行时(2)

    JVM-从字节码到运行时(2) 基于栈的解释器执行过程 这是例子ByteCodeDemo类中的add(int z)...

  • JVM-对象内存布局

    jvm-对象内存布局 对象内存结构概述 对象的创建过程: jvm将对象所在的class文件加载到方法区中 jvm读...

  • JVM-从字节码到运行时(1)

    JVM-从字节码到运行时(1) 一切从javap -verbose开始 希望借此文章将Class文件结构和运行时的...

  • JVM-线程状态

    JVM的线程状态的功能是用于监控,不能用作实质性控制。linux中的这四个状态在java的线程状态中没有对应"D ...

网友评论

      本文标题:JVM-理论

      本文链接:https://www.haomeiwen.com/subject/ddpemktx.html