文章目录

  • 参考文档
  • Jvm体系结构图
  • Jvm 垃圾回收(garbage collection)
    • 1. 如何确定一个对象是垃圾
      • 1.1 引用计数法
      • 1.2 可达性分析
    • 2. 垃圾回收算法
      • 2.1 标记清除算法
      • 2.2 复制算法
      • 2.3 标记整理
    • 3. 分代收集算法
    • 4. HotSpot的垃圾收集器
      • 4.1 Serial收集器
      • 4.2 ParNew收集器
      • 4.3 Parallel Scavenge收集器(1.8默认使用)
      • 4.4 Serial Old收集器
      • 4.5 Parallel Old收集器
      • 4.6 CMS收集器(jdk1.5默认收集器)
      • 4.7 G1收集器(Garbage - First:垃圾优先;jdk 9默认收集器)
  • Jvm调优
    • 1.1 收集器分析
    • 1.2 怎么查看有哪些可配置参数?
    • 1.3 调优参数类型
    • 1.4 分析工具
    • 1.5 常用命令
    • 1.6 常用参数含义

参考文档

  • OpenJdk官网地址
  • 垃圾回收文档介绍

Jvm体系结构图

Jvm 垃圾回收(garbage collection)

1. 如何确定一个对象是垃圾

  • 想要了解垃圾回收,必须清楚什么事垃圾

1.1 引用计数法

在对象创建时,会生成引用计数器,占用4个字节,创建时即为1

获得retain消息时会加1,获得release消息时会减1

  1. 对于某个对象而言,只要应用程序中持有该对象的引用,就说明该对象不是垃圾

  2. 对象被引用时,引用计数器加一

  3. 如果一个对象没有任何指针对其引用,它就是垃圾

  4. 弊端:对于两个对象相互引用的case,会导致永远无法回收

    /*** 引用计数算法,判断对象是否为垃圾(可回收)*/
    public class JudgeGarbageDemo1 {public static void main(String[] args) {JudgeGarbageObj obj1 = new JudgeGarbageObj();//创建对象,局部变量入栈,引用计数器+1=1JudgeGarbageObj obj2 = new JudgeGarbageObj();//创建对象,局部变量入栈,引用计数器+1=1obj1.obj = obj2;//obj2 被 obj1引用,obj2的引用计数器+1 = 2obj2.obj = obj1;//obj1 被 obj2引用,obj1的引用计数器+1 = 2obj1 = null;//obj1 栈中的引用释放,引用计数器-1 = 1obj2 = null;//obj2 栈中的引用释放,引用计数器-1 = 1//obj1 和 obj2 在引用计数算法来判断是否为垃圾,则无法被回收且不可达,内存泄露}
    }
    

1.2 可达性分析

  • 通过GC Root的对象,向下查找,能找到的对象即可达对象,否则视为垃圾
  • 能作为GC Root:
    • 类加载器:由系统类加载器(system class loader)加载的对象
    • 虚拟机栈的本地变量表(栈包含:本地变量表,操作数栈、栈针:(动态链接,返回地址,即时信息))
    • 常量池中的引用等

2. 垃圾回收算法

2.1 标记清除算法

  1. 标记:找出内存中需要回收的对象并标记(此操作需要扫描堆中所有数据,才能确定要回收的对象,比较耗时)
  2. 清除:清除需要被回收的对象,释放内存空间
  3. 缺点
    1. 标记和清除两个过程都比较耗时,影响性能
    2. 清除内存后,会产生内存碎片,内存利用率下降

2.2 复制算法

  1. 将内存划分为两块相等的区域,每次只使用其中一个
  2. 当正在使用的区域1无可用内存时,将仍存活的内存复制到另一块区域2,清除1内的数据
  3. 优点:清除效率较快;缺点:内存利用率很低

2.3 标记整理

  1. 标记过程仍然与"标记-清除"算法一样,但是后续步骤不是直接对可回收对象进行清理,而是让所有存活

    的对象都向一端移动,然后直接清理掉端边界以外的内存

3. 分代收集算法

  1. young区:复制算法(对象在被分配之后,可能生命周期比较短_oracle官方统计98%的对象时朝生夕死,Young区复制效率比较高)

    1. 抛出个问题:如果MinorGc时S0区不够用,会怎样???

      • 分配担保机制
  2. old区:标记清除或标记整理(Old区对象存活时间比较长,复制来复制去没必要)

4. HotSpot的垃圾收集器

  • 基于算法理论知识的落地实现

4.1 Serial收集器

  • Serial是jdk1.3.1之前新生代垃圾回收的唯一选择

  • Serial是一种单线程收集器,所以在垃圾回收的过程中会全程STW

    优点:简单高效,拥有很高的单线程收集效率 (高效是指未出现多核cpu出现的阶段->单核的情况)
    缺点:收集过程需要暂停所有线程
    算法:复制算法
    适用范围:新生代
    

4.2 ParNew收集器

  • 可以理解为Serial的多线程版本

    优点:在多CPU时,比Serial效率高。
    缺点:收集过程暂停所有应用程序线程,单CPU时比Serial效率差。
    算法:复制算法
    适用范围:新生代
    

4.3 Parallel Scavenge收集器(1.8默认使用)

  • 以停顿时间&吞吐量为优先关注点

  • 该收集器是一个新生代收集器,使用复制算法并且是多线程收集器,看着个ParNew差不多,但它关注的是系统的吞吐量

    # 吞吐量=运行用户代码的时间/(运行用户代码的时间+垃圾收集时间)
    # 比如虚拟机总共运行了100分钟,垃圾收集时间用了1分钟,吞吐量=(100-1)/100=99%。
    # 若吞吐量越大,意味着垃圾收集的时间越短,则用户代码可以充分利用CPU资源,尽快完成程序的运算任务。
    -XX:MaxGCPauseMillis控制最大的垃圾收集停顿时间,
    -XX:GCTimeRatio直接设置吞吐量的大小。# 开启了自适应开关,jvm会自动调整配置大小,包含xms和xmx
    -XX:+UseAdaptiveSizePolicy
    
  • 需要解释的事,设置了最大停顿时间并不代表一定小于改时间,收集器会尽量保证停顿时间小于设置的值

  • 原理,通过自适应调整分区的大小来实现

4.4 Serial Old收集器

  • Serial Old收集器是Serial收集器的老年代版本,也是一个单线程收集器,不同的是采用"标记-整理算法"。

4.5 Parallel Old收集器

  • Parallel Old收集器是Parallel Scavenge收集器的老年代版本,使用多线程和"标记-整理算法"进行垃圾回收

4.6 CMS收集器(jdk1.5默认收集器)

  • 描述:CMS(Concurrent Mark Sweep)收集器是一种以获取 最短回收停顿时间 为目标的收集器。采用的是"标记-清除算法"

  • 整个过程分为4步

    (1)初始标记 CMS initial mark 标记GC Roots能关联到的对象 Stop The World-- ->速度很快 1.8之后初始标记是并发进行(-XX:+CMSParallelInitialMarkEnable开关)
    (2)并发标记 CMS concurrent mark 进行GC Roots Tracing
    (3)重新标记 CMS remark 修改并发标记因用户程序变动的内容 Stop The World
    (4)并发清除 CMS concurrent sweep
    
  • 整体过程如图(并发预处理不在图中_列入并发标记中,也是标记操作)

  • 重新标记:是重新全量扫描吗?

    • CMS将Old区分为多个块(分区管理)

    • 在并发标记新产生的对象所在的块会在card table进行记录(card table管理跨代引用)

      • Obj1.obj = Obj2,会在Obj1的对象中开辟空间记录Obj2的引用
    • 然后对表示的对象进行重新扫描即可

  • 回收阈值:

    #开启设置回收阈值生效(不开启的话,回收阈值的配置只会生效一次)
    -XX:+UseCMSInitiatingOccupancyOnly
    #设置触发回收阈值(int类型 1-100 ),默认不开启,值为-1
    -XX:CMSInitiatingOccupancyFraction=80
    #----------------------------------------
    #如果未开启回收阈值,则使用公式结果来触发
    # ((100 - MinHeapFreeRatio)+ (double)(CMSTriggerRatio * MinHeapFreeRatio) )/100
    
  • 内存整理:

    #开启old区内存整理(默认开启)
    -XX:+UseCMSCompactAtFullCollection
    #设置在几次full gc后进行内存整理(默认0,每次都整理)
    -XX:CMSFullGCsBeForeCompaction
    
  • 自适应策略:

    # 开启了自适应开关,jvm会自动调整配置大小,包含xms和xmx
    -XX:+UseAdaptiveSizePolicy
    
  • 优点:并发收集、低停顿、具有担保机制;追求快

  • 缺点

    • 单核或双核的硬件下,效率低
    • 预处理阶段最长会5秒钟,效率低
    • 并发阶段会降低吞吐量:gc整体时间延长
    • 全量扫描堆,包含新生代
      • 并发预处理等待一次young gc后(young gc的结果必须小于配置值)继续重新标记,最多等待5秒
      • CMSScheduleRemarkEdenPenetration 百分比 CMSScheduleRemarkEdenSizeThreshold大小
    • 并发不能保证:并发阶段会产生新的垃圾,CMS必须要在堆内存满之前完成gc,
      • 否则并发模式background失败,将触发担保机制foreg ound模式
      • 收集器切换到serial收集器(串行收集,全过程STW)
    • 标记清楚算法无法对内存碎片进行整理,会产生较多的碎片

4.7 G1收集器(Garbage - First:垃圾优先;jdk 9默认收集器)

  • 官网介绍地址

  • 简述

    G1收集器,Java堆的内存布局与其他收集器有很大差别,它将整个Java堆划分为多个大小相等的独立区域(Region),虽然还保留有新生代和老年代的概念,但新生代和老年代不再是物理隔离的了,它们都是一部分Region(不需要连续)的集合。

    尽可能多的回收更多的垃圾

  • 内存模型(将内存划分为多个Region区)

    • Humongous:大对象区

  • Region区:逻辑分区、可转换角色;参数控制每个区1-32M(jdk 8中);默认有2048个Region

    • 所以最小堆内存是 1M * 2048 = 2G ?? 会根据最大堆内存和最小堆内存的平均值计算出Region大小和卡表的大小
    • CardTable卡表:计算每个Region的状态
    • Rset(RememberSet)即引用集 :记录引用关系,有两种方式,eg:Obj1.obj = Obj2
      • point out:会在Obj1的对象中开辟空间记录Obj2的引用(CMS)
      • point in:在Obj2的对象中开辟空间记录Obj1(G1使用模式)
    • 角色可转换(Region的reset的一部分功能)
  • 三色标记算法(SATB - Snapshot-At-The-Beginning)_简单描述

    • 将不同状态的对象标记不同的颜色,例如
    • 将已扫描完成的对象标记为黑色
    • 将正在扫描的对象标记为灰色
    • 将未扫描的对象标记为白色(可回收的对象)
  • 对象分配流程(快速分配,慢速分配)

    • TLAB简述:Thread Local Allocation Buffer,线程本地分配缓冲区(线程专用的内存分配区域)
    • 默认TLAB是开启的 ,配置参数 -XX:+UseTLAB
    • 通过参数:-XX:TLABWasteTargetPercent设置TLAB空间所占用Eden空间的百分比大小
    • 开启后,在每个线程初始化时,会申请一块指定大小的内存,只给当前线程使用,这样每个线程都单独拥有一个空间,如果需要分配内存,就在自己的空间上分配

  • 再次分配新的TLAB解释:对TLAB可以设置最大浪费空间,当TLAB空间小于最大浪费空间且所需空间不够用,则可以申请空间

  • 如何完成可预测时间停顿

    • 经过价值分析(算法),优先回收价值高的region
  • 如果解决空间碎片

    • region的角色可以变更
  • 自适应策略:

    • 在xms和xmx的基础上进行调优
  • 特点

    • 并发与并行
    • 分代收集
    • 空间整合(整体上属于“标记-整理”算法(局部复制算法),不会导致空间碎片)
    • 可预测的停顿(Parallel Old收集器的特性)
  • 工作过程:

    • 初始标记: 标记一下GC Roots能够关联的对象,并且修改TAMS的值,需要暂停用户线程
    • 并发标记: 从GC Roots进行可达性分析,找出存活的对象,与用户线程并发执行
    • 最终标记: 修正在并发标记阶段因为用户程序的并发执行导致变动的数据,需暂停用户线程
    • 筛选回收: 对各个Region的回收价值和成本进行排序,根据用户所期望的GC停顿时间制定回收计划

Jvm调优

1.1 收集器分析

  • ParNew

    • 内存小于6G
    • cpu小于4核
    • 对gc时间没有硬性要求的可以使用
  • Parallel Scavenge

    • 内存小于6G
    • cpu小于4核
    • 对STW时间有这较高的要求
    • 需要控制gc的吞吐率,整体gc占用时间比
  • CMS收集器

    • cup>=4核
    • 追求gc时间越短越好
    • 最小堆内存6G
      • 堆内存太小会造成频繁gc
      • S区太小会造成存活对象提前进入Old区
      • Old区取消了整理阶段,会产生内存碎片,到时容易触发FullGC
      • Old区不够用时会触发担保机制,使用Serial Full GC来回收
      • 抢占cpu资源的成本更大
  • G1收集器

    • cup>=4核

    • 对STW时间有这较高的要求

    • 需要控制gc的吞吐率,整体gc占用时间比

    • 最小对内存6G:G1的第一个重点是为运行需要大量GC延迟的应用程序的用户提供一个解决方案。这意味着堆大小约为6GB或更大,并且稳定且可预测的暂停时间低于0.5秒。

      • 超过50%的Java堆被存活对象占用
      • 大对象比较都的情况下
      • 垃圾回收时间较长,大于0.5到1s
      • 参考文档:https://docs.oracle.com/javase/8/docs/technotes/guides/vm/G1.html#use_cases
    • 建议设置-xmn设置年轻代大小或-XX:NewRatio设置年轻代与老年代的比例(会影响自适应调整内存策略,影响吞吐量)

      • 参考文档:https://docs.oracle.com/javase/8/docs/technotes/guides/vm/gctuning/g1_gc_tuning.html#recommendations
    • 建议只调整低停顿、高吞吐量的参数;没有特殊的需求,自适应一般比配置的好

1.2 怎么查看有哪些可配置参数?

  • 查看jvm支持哪些参数:

    #VM options中开启输出jvm支持的flags
    -XX:+PrintFlagsFinal
    
  • 可查看目前开启了哪些配置

  • 查看哪些配置被修改过: :=代表修改过; = 代表未修改过

1.3 调优参数类型

  • Boolean类型;例如 -XX:+UseCMSInitiatingOccupancyOnly 开启阈值设置项

    • +代表开启,-代表不开启
  • kv类型;例如 -XX:CMSInitiatingOccupancyFraction=80 阈值设置为80%

    • v的取值范围0-100
  • https://docs.oracle.com/javase/8/docs/technotes/guides/vm/gctuning/)

1.4 分析工具

  • 分析gc日志工具:https://gceasy.io

  • mat下载地址:http://www.eclipse.org/mat/downloads.php

  • Jconsole、jvisualvm

    • 可查看jvm实时或历史的堆、类加载、cpu、线程状态信息
  • Arthas(阿里开源)

    • github地址:https://github.com/alibaba/arthas
    • 可随时打开和关闭监控开关,不占用服务器任何资源
    • 不仅可以监控,还有诊断的能力
    • 已有100多家大型公司接入

1.5 常用命令

  • jps -l 查看java进程

  • jinfo 查看jvm的参数和实时调整参数(ps -ef也能把参数显示出来)

    • jinfo -flags pid 查看进程所有jvm参数配置

    • jinfo -flag name pid 查看某个java进程的name属性的值

      jinfo -flags pid
      jinfo -flag MaxHeapSize pid
      jinfo -flag UseG1GC pid
      

    • 实时修改jvm参数

      • -flag [+|-] pid:设置指定JVM参数的布尔值

      • -flag = pid:设置指定JVM参数的值

        jinfo -flag +PrintGC pid
        jinfo -flag MaxHeapSize=1024 pid
        
  • Jstat、jstack、jmap等

    jmap -dump:format=b,file=heap.hprof PID
    

1.6 常用参数含义

  • -XX:CICompilerCount=3 最大并行编译数 如果设置大于1,虽然编译速度会提高,但是同样影响系统稳定性,会增加JVM崩溃的可能

  • -XX:InitialHeapSize=100M 初始化堆大小 简写-Xms100M

  • -XX:MaxHeapSize=100M 最大堆大小 简写-Xmx100M

  • -XX:NewSize=20M 设置年轻代的大小

  • -XX:MaxNewSize=50M 年轻代最大大小

  • -XX:OldSize=50M 设置老年代大小

  • -XX:MetaspaceSize=50M 设置方法区大小

  • -XX:MaxMetaspaceSize=50M 方法区最大大小

  • -XX:+UseParallelGC 使用UseParallelGC 新生代,吞吐量优先

  • -XX:+UseParallelOldGC 使用UseParallelOldGC 老年代,吞吐量优先

  • -XX:+UseConcMarkSweepGC 使用CMS 老年代,停顿时间优先

  • -XX:+UseG1GC 使用G1GC 新生代,老年代,停顿时间优先

  • -XX:NewRatio 新老生代的比值 比如-XX:Ratio=4,则表示新生代:老年代=1:4,也就是新生代占整个堆内存的1/5

  • -XX:SurvivorRatio 两个S区和Eden区的比值 比如-XX:SurvivorRatio=8,也就是(S0+S1):Eden=2:8

  • -XX:+HeapDumpOnOutOfMemoryError 启动堆内存溢出打印

  • -XX:HeapDumpPath=heap.hprof 指定堆内存溢出打印目录 表示在当前目录生成一个heap.hprof文件

  • 打印出GC日志 可以使用不同的垃圾收集器,对比查看GC情况

    • XX:+PrintGCDetails -
    • XX:+PrintGCTimeStamps
    • XX:+PrintGCDateStamps
    • Xloggc:$CATALINA_HOME/logs/gc.log
  • -Xss128k 设置每个线程的堆栈大小 一般是3000-5000最佳

  • -XX:MaxTenuringThreshold=6 提升年老代的最大临界值 默认值为 15

  • -XX:InitiatingHeapOccupancyPercent 启动并发GC周期时堆内存使用占比;G1之类的垃圾收集器用它来触发并发GC周期,基于整个堆的使用率,而不只是某一代内存的使用比. 值为 0 则表示”一直执行GC循环”. 默认值为 45.

  • -XX:G1HeapWastePercent 允许的浪费堆空间的占比 默认是10%,如果并发标记可回收的空间小于10%,则不会触发MixedGC。

  • -XX:MaxGCPauseMillis=200ms G1最大停顿时间;暂停时间不能太小,太小的话就会导致出现G1跟不上垃圾产生的速度。最终退化成Full GC。

  • -XX:ConcGCThreads=n 并发垃圾收集器使用的线程数量 默认值随JVM运行的平台不同而不同

Jvm垃圾收集器调优工具调优指南相关推荐

  1. 直通BAT必考题系列:7种JVM垃圾收集器特点,优劣势、及使用场景

    直通BAT之JVM系列 直通BAT必考题系列:JVM的4种垃圾回收算法.垃圾回收机制与总结 直通BAT必考题系列:深入详解JVM内存模型与JVM参数详细配置 今天继续JVM的垃圾回收器详解,如果说垃圾 ...

  2. 7种 JVM 垃圾收集器特点、优劣势及使用场景(多图)

    点击上方"IT牧场",选择"设为星标"技术干货每日送达! 一.常见垃圾收集器 现在常见的垃圾收集器有如下几种: 新生代收集器: Serial ParNew Pa ...

  3. JVM垃圾收集器(三)

    JVM垃圾收集器(三) 垃圾回收(GC)线程与应用线程保持相对独立,当系统需要执行垃圾回收任务时,先停止工作线程,然后命令GC线程工作,以串行模式工作的收集器,称为Serial Collector,即 ...

  4. 7种JVM垃圾收集器特点,优劣势、及使用场景,Java-SSM框架相关面试题整理

    Serial 是一款用于新生代的单线程收集器,采用复制算法进行垃圾收集.Serial 进行垃圾收集时,不仅只用一条线程执行垃圾收集工作,它在收集的同时,所有的用户线程必须暂停(Stop The Wor ...

  5. JVM垃圾收集器——G1

    导航 引言 一.G1 介绍 1.1 适用场景 1.2 设计初衷 1.3 关注焦点 1.4 工作模式 1.5 堆的逻辑结构 1.6 主要收集目标 1.7 停顿预测模型 1.8 拷贝和压缩 1.9 与 C ...

  6. JVM优化系列-JVM垃圾收集器介绍

    导语   既然是串行顾名思义就是使用单线程的方式进行执行,每次执行回收的时候,串行回收器只有一个工作线程,这样对于并行能力较弱的计算机,串行回收器更多的独占线程专一执行的方面有着良好的实现,也就是说在 ...

  7. JVM 垃圾收集器 学习笔记(《深入理解java虚拟机》之六 垃圾收集)

    目录 新生代收集器 Serial收集器 ParNew收集器 Parallel Scavenge收集器 老年代收集器 Serial Old收集器 Parallel Old收集器 CMS收集器 Remov ...

  8. 面试题:JVM垃圾收集器

    GC的性能指标 吞吐量:运行用户代码的时间占总运行时间的比例. 暂停时间:执行垃圾收集时,程序工作线程被暂停的时间. 内存占用:Java堆区所占的内存大小. 高吞吐量较好因为这会让应用程序的用户感觉应 ...

  9. JVM垃圾收集器详解 CMS、G1、Shenandoah、ZGC

    上一篇我们讲解了一些垃圾回收的理论和一些基础的算法和思想,这一篇主要是jvm从古至今垃圾收集器的实现. 各垃圾回收器 注:有连线的代表他们可以互相配合使用. Serial和Serial Old收集器 ...

最新文章

  1. ASP.NET 发邮件方法
  2. (原创)无废话C#设计模式之十二:Bridge
  3. 病毒研究之感染linux脚本
  4. 【项目管理】ITTO-进度管理
  5. 【深度学习】深度学习经典数据集汇总
  6. CVPR 2022|从原理和代码详解FAIR的惊艳之作:全新的纯卷积模型ConvNeXt
  7. 一致性hash算法原理
  8. CF1547F Array Stabilization (GCD version) st表 + 尺取/二分
  9. 谷歌离开游览器不触发_谷歌游览器
  10. mysql 查询一个月的时间_mysql日期查询sql语句总结(查询一天,查询一周,查询一个月的数据)...
  11. 2021高考成绩查询。,2021高考成绩公布时间 2021高考成绩查询方式
  12. Hadoop-2.0命令手册
  13. 孟山都公司董事长兼CEO休-格兰特出席2017年中国发展高层论坛
  14. [数据结构] 配对堆
  15. 记一次spirngMVC整合HttpPrinter的过程
  16. fspecial,imfilter
  17. 卸载密码保护的瑞星网络版
  18. 线性波传播至垂直壁面反射形成驻波的动画MATLAB程序
  19. CS5263|DP转HDMI 4K60HZ转换方案|DP转HDMI 2.0转换电路
  20. 十六进制字符串转中文

热门文章

  1. 打造千万级流量系统——秒杀系统(需求篇)
  2. 请问你如何理解以下的歌词“unravel - TK from 凛冽时雨 (TK from 凛として時雨)为什么很多人说崖山海战以后无中国
  3. Tomcat软件启动时闪退
  4. VisualStudio相关序列号
  5. 构造函数(静态成员)(实例成员)
  6. 联发科芯片趋势
  7. 单链表结构与顺序存储结构优缺点
  8. 建立DNS隧道绕过校园网认证
  9. 拼多多中秋美食一降到底|一度智信
  10. 【Java成王之路】EE初阶第十四篇:(网络原理) 4