01 Garbage Collect(垃圾回收)

  1.1 如何确定一个对象是垃圾?

    要想进行垃圾回收,得先知道什么样的对象是垃圾。

    1.1.1 引用计数法

      对于某个对象而言,只要应用程序中持有该对象的引用,就说明该对象不是垃圾,如果一个对象没有任何指针对其引用,它就是垃圾。
      弊端 :如果AB相互持有引用,导致永远不能被回收。
    

     1.1.2 可达性分析 
      通过GC Root的对象,开始向下寻找,看某个对象是否可达 
  

  1. 能作为GC Root:类加载器、Thread、虚拟机栈的本地变量表、static成员、常量引用、本地方法
  2. 栈的变量等。
1.2 垃圾收集算法
  1. 已经能够确定一个对象为垃圾之后,接下来要考虑的就是回收,怎么回收呢?
  2. 得要有对应的算法,下面聊聊常见的垃圾回收算法
1.2.1 标记-清除(Mark-Sweep)
找出内存中需要回收的对象,并且把它们标记出来 

清除掉被标记需要回收的对象,释放出对应的内存空间 

缺点
  1. 标记清除之后会产生大量不连续的内存碎片,空间碎片太多可能会导致以后在程 序运行过程中需要分配较大对象时,无法找到足够的连续内存而不得不提前触发另一次垃圾收集动作。
  2. (1)标记和清除两个过程都比较耗时,效率不高
    (2)会产生大量不连续的内存碎片,空间碎片太多可能会导致以后在程序运行过程中需要分配较大对象时,无 法找到足够的连续内存而不得不提前触发另一次垃圾收集动作。
1.2.2 复制(Copying)
将内存划分为两块相等的区域,每次只使用其中一块

当其中一块内存使用完了,就将还存活的对象复制到另外一块上面,然后把已经使用过的内存空间一次清除掉

缺点: 空间利用率降低
 
1.2.3 标记-整理(Mark-Compact)

标记过程仍然与"标记-清除"算法一样,但是后续步骤不是直接对可回收对象进行清理,而是让所有存活
的对象都向一端移动,然后直接清理掉端边界以外的内存

让所有存活的对象都向一端移动,清理掉边界意外的内存。

1.3 分代收集算法
既然上面介绍了3中垃圾收集算法,那么在堆内存中到底用哪一个呢?
Young区:复制算法(对象在被分配之后,可能生命周期比较短,Young区复制效率比较高)
Old区:标记清除或标记整理(Old区对象存活时间比较长,复制来复制去没必要,不如做个标记再清理)
1.4 垃圾收集器
如果说收集算法是内存回收的方法论,那么垃圾收集器就是内存回收的具体实现,说白了就是落地咯。

1.4.1 Serial收集器 

Serial收集器是最基本、发展历史最悠久的收集器,曾经(在JDK1.3.1之前)是虚拟机新生代收集的唯
一选择。
它是一种单线程收集器,不仅仅意味着它只会使用一个CPU或者一条收集线程去完成垃圾收集工作,更
重要的是其在进行垃圾收集的时候需要暂停其他线程

  1. 优点:简单高效,拥有很高的单线程收集效率
  2. 缺点:收集过程需要暂停所有线程
  3. 算法:复制算法
  4. 适用范围:新生代
  5. 应用:Client模式下的默认新生代收集器

1.4.2 ParNew收集器 
可以把这个收集器理解为Serial收集器的多线程版本。
  1. 优点:在多CPU时,比Serial效率高。
  2. 缺点:收集过程暂停所有应用程序线程,单CPU时比Serial效率差。
  3. 算法:复制算法
  4. 适用范围:新生代
  5. 应用:运行在Server模式下的虚拟机中首选的新生代收集器

1.4.3 Parallel Scavenge收集器

Parallel Scavenge收集器是一个新生代收集器,它也是使用复制算法的收集器,又是并行的多线程收集
器,看上去和ParNew一样,但是Parallel Scanvenge更关注 系统的吞吐量 。

  1. 吞吐量=运行用户代码的时间/(运行用户代码的时间+垃圾收集时间)
  2. 比如虚拟机总共运行了100分钟,垃圾收集时间用了1分钟,吞吐量=(100-1)/100=99%。
  3. 若吞吐量越大,意味着垃圾收集的时间越短,则用户代码可以充分利用CPU资源,尽快完成程序
  4. 的运算任务。
  1. -XX:MaxGCPauseMillis控制最大的垃圾收集停顿时间,
  2. -XX:GCTimeRatio直接设置吞吐量的大小。
1.4.4 Serial Old收集器

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

1.4.5 Parallel Old收集器 

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

吞吐量优先
1.4.6 CMS收集器
CMS(Concurrent Mark Sweep)收集器是一种以获取 最短回收停顿时间 为目标的收集器。
采用的是"标记-清除算法",整个过程分为4步
  1. (1)初始标记 CMS initial mark 标记GC Roots能关联到的对象 Stop The World-- ->速度很快
  2. (2)并发标记 CMS concurrent mark 进行GC Roots Tracing
  3. (3)重新标记 CMS remark 修改并发标记因用户程序变动的内容 Stop The World
  4. (4)并发清除 CMS concurrent sweep

采用的是"标记-清除算法",整个过程分为4步由于整个过程中,并发标记和并发清除,收集器线程可以与用户线程一起工作,所以总体上来
说,CMS收集器的内存回收过程是与用户线程一起并发地执行的。

  1. 优点:并发收集、低停顿
    缺点:产生大量空间片、并发阶段会降低吞吐量

1.4.7 G1收集器 
G1特点 
  1. 并行与并发
  2. 分代收集(仍然保留了分代的概念)
  3. 空间整合(整体上属于“标记-整理”算法,不会导致空间碎片)
  4. 可预测的停顿(比CMS更先进的地方在于能让使用者明确指定一个长度为M毫秒的时间片段内,消耗在垃圾收集 上的时间不得超过N毫秒)
  1. 使用G1收集器时,Java堆的内存布局与就与其他收集器有很大差别,它将整个Java堆划分为多个
  2. 大小相等的独立区域(Region),虽然还保留有新生代和老年代的概念,但新生代和老年代不再
  3. 是物理隔离的了,它们都是一部分Region(不需要连续)的集合
工作过程可以分为如下几步 
  1. 初始标记(Initial Marking 标记一下GC Roots能够关联的对象,并且修改TAMS的值,需要暂 停用户线程
  2. 并发标记(Concurrent Marking GC Roots进行可达性分析,找出存活的对象,与用户线程并发 执行
  3. 最终标记(Final Marking 修正在并发标记阶段因为用户程序的并发执行导致变动的数据,需 暂停用户线程
  4. 筛选回收(Live Data Counting and Evacuation 对各个Region的回收价值和成本进行排序,根据 用户所期望的GC停顿时间制定回收计划

1.4.8 垃圾收集器分类
串行收集器->Serial和Serial Old 
  1. 只能有一个垃圾回收线程执行,用户线程暂停。 适用于内存比较小的嵌入式设备
并行收集器[吞吐量优先]->Parallel Scanvenge、Parallel Old
  1. 多条垃圾收集线程并行工作,但此时用户线程仍然处于等待状态。 适用于科学计算、后台处理等若交互场景
并发收集器[停顿时间优先]->CMS、G1 
  1. 用户线程和垃圾收集线程同时执行(但并不一定是并行的,可能是交替执行的),垃圾收集线程在执行的
  2. 时候不会停顿用户线程的运行。 适用于相对时间有要求的场景,比如Web
1.4.9 理解吞吐量和停顿时间 

停顿时间->垃圾收集器 进行 垃圾回收终端应用执行响应的时间
吞吐量->运行用户代码时间/(运行用户代码时间+垃圾收集时间)

  1. 停顿时间越短就越适合需要和用户交互的程序,良好的响应速度能提升用户体验;
    高吞吐量则可以高效地利用CPU时间,尽快完成程序的运算任务,主要适合在后台运算而不需要太多交互的任 务。
小结 :这两个指标也是评价垃圾回收器好处的标准,其实调优也就是在观察者两个变量。 
 
1.4.10 如何选择合适的垃圾收集器 

官网 :https://docs.oracle.com/javase/8/docs/technotes/guides/vm/gctuning/collectors.html#sthr
ef28

  1. 优先调整堆的大小让服务器自己来选择
  2. 如果内存小于100M,使用串行收集器
  3. 如果是单核,并且没有停顿时间要求,使用串行或JVM自己选
  4. 如果允许停顿时间超过1秒,选择并行或JVM自己选
  5. 如果响应时间最重要,并且不能超过1秒,使用并发收集器
  6. 对于G1收集
1.4.11 再次理解G1
JDK 7开始使用,JDK 8非常成熟,JDK 9默认的垃圾收集器,适用于新老生代。
判断是否需要使用G1收集器? 
  1. 150%以上的堆被存活对象占用
  2. 2)对象分配和晋升的速度变化非常大
  3. 3)垃圾回收时间比较长
1.4.12 如何开启需要的垃圾收集
  1. 1)串行 -XX:+UseSerialGC -XX:+UseSerialOldGC
  2. 2)并行(吞吐量优先): -XX:+UseParallelGC -XX:+UseParallelOldGC
    3)并发收集器(响应时间优先) -XX:+UseConcMarkSweepGC -XX:+UseG1G

JVM升华篇的更多相关文章

  1. 初步了解JVM第二篇

    在一篇<初步了解JVM第一篇>中,我们已经了解了: 类加载器:负责加载*.class文件,将字节码内容加载到内存中.其中类加载器的类型有如下: 启动类加载器(Bootstrap) 扩展类加 ...

  2. JVM学习篇-第一篇

    JVM学习篇-第一篇 JDK( Java Development Kit): ​ Java程序设计语言.Java虚拟机.Java类库三部分统称为JDK,JDK是用于支持Java程序开发的最小环境** ...

  3. JVM执行篇:使用HSDIS插件分析JVM代码执行细节--转

    http://www.kuqin.com/java/20111031/314144.html 在<Java虚拟机规范>之中,详细描述了虚拟机指令集中每条指令的执行过程.执行前后对操作数栈. ...

  4. JVM前奏篇(大局观)

    话不多说直接上干货,先来看oracle官网中是怎么描述JDK的:https://docs.oracle.com/javase/8/docs/index.html 这是官网中JDK.JRE.JVM的一个 ...

  5. 初步了解JVM第一篇

    大家都知道,Java中JVM的重要性,学习了JVM你对Java的运行机制.编译过程和如何对Java程序进行调优相信都会有一个很好的认知. 废话不多说,直接带大家来初步认识一下JVM. 什么是JVM? ...

  6. 1.JVM前奏篇(看官网怎么说)

    JVM(Java Virtual Machine) 前奏篇(看官网规范怎么说) 1.The relation of JDK/JRE/JVM 在下图中,我们所接触的,最熟悉,也是经常打交道的 最顶层 J ...

  7. JVM 第二篇:垃圾收集器以及算法

    本文内容过于硬核,建议有 Java 相关经验人士阅读. 0. 引言 一说到 JVM ,大多数人第一个想到的可能就是 GC ,今天我们就来聊一聊和 GC 关系最大的垃圾收集器以及垃圾收集算法,希望能通过 ...

  8. 【JVM第二篇--类加载机制】类加载器与双亲委派模型

    写在前面的话:本文是在观看尚硅谷JVM教程后,整理的学习笔记.其观看地址如下:尚硅谷2020最新版宋红康JVM教程 一.什么是类加载器 在类加载过程中,加载阶段有一个动作是"通过一个类的全限 ...

  9. 深入理解JAVA虚拟机之JVM性能篇---垃圾回收

    一.基本垃圾回收算法 1. 判断对象是否需要回收的方法(如何判断垃圾): 1) 引用计数(Reference Counting)  对象增加一个引用,即增加一个计数,删除一个引用则减少一个计数.垃圾回 ...

随机推荐

  1. RecyclerView 源码分析(二) —— 缓存机制

    在前一篇文章 RecyclerView 源码分析(一) -- 绘制流程解析 介绍了 RecyclerView 的绘制流程,RecyclerView 通过将绘制流程从 View 中抽取出来,放到 Lay ...

  2. zabbix客户端监控脚本shell

    zabbix客户端监控脚本shell #!/bin/sh sleep 3 zabbixdir=`pwd` zabbix_version=4.2.5 ###指定版本,最好和server端吻合版本,可以自 ...

  3. jQuery 移入显示div,移出当前div,移入到另一个div还是显示。

    jQuery 移入移出 操作div 1 <style type="text/css"> 2 .box{ 3 position: relative; 4 } 5 .box ...

  4. testng学习笔记-- beforesuit和aftersuit

    一.定义 测试套件,主要关注执行顺序 套件:suit可以包含多个class 二.代码标签 三.运行结果

  5. Linux服务器内存池技术是如何实现的

    Linux服务器内存池技术是如何实现的

  6. ETL优化(转载)

    1.引言 数据仓库建设中的ETL(Extract, Transform, Load)是数据抽取.转换和装载到模型的过程,整个过程基本是通过控制用SQL语句编写的存储过程和函数的方式来实现对数据的直接操 ...

  7. Defining Go Modules

    research!rsc: Go & Versioning https://research.swtch.com/vgo shawn@a:~/gokit/tmp$ go get --helpu ...

  8. WireGuard 教程:使用 DNS-SD 进行 NAT-to-NAT 穿透

    原文链接:https://fuckcloudnative.io/posts/wireguard-endpoint-discovery-nat-traversal/ WireGuard 是由 Jason ...

  9. 无刷电调基础知识以及BLHeli固件烧录和参数调整

    标题: 无刷电调基础知识以及BLHeli固件烧录和参数调整 作者: 梦幻之心星 sky-seeker@qq.com 标签: [#基础知识,#电调,#BLHeli,#固件,#烧录,#调参] 目录: [电 ...

  10. 五:Spring Security 中的角色继承问题

    Spring Security 中的角色继承问题 以前的写法 现在的写法 源码分析 SpringSecurity 在角色继承上有两种不同的写法,在 Spring Boot2.0.8(对应 Spring ...