JVM3 安全点/安全区/垃圾回收器

PART ONE:HotSpot的算法实现

枚举根节点:

可达性分析找引用链的过程,可以作为GCRoot 节点的引用,一本为全局引用(静常量或者静态引用)和执行上下文(栈帧中的本地变量表),要逐个检查里面有没有引用,势必会消耗很多时间

可达性分析的敏感点在于时间的停顿,因为再进行这项操作的时候必须要保持一致性,”一致性:“整个执行系统看起来象被冻结了一样停顿早某个时间点,不可以出现在进行可达性分析的过程中,对象之间的引用关系还在变化。这就要求GC进行时必须要停顿Java的所有执行线程(就算再号称几乎不会发生停顿的CMS收集器中,枚举根节点时的停顿也是必须的

现在的Java虚拟机都是标准的GC,所以当线程停下来枚举根节点时,并不需要一个不漏的检查所有的执行上下文和全局引用的地方,在HotSpot 的实现中,提供了一种数据结构OopMap ,在类加载的完成时就把对象中什么偏移量是什么类型的数据计算出来,当GC扫描时就可以直接得到这些信息。

安全点

在程序执行的时候并非所有时候都能停顿下来开始GC ,只有到达安全点才能暂停。安全点的选择标准:是否具有让程序长时间执行的特征,例如:方法调用,循环跳转,一场跳动等。具有这些功能的指令才会产生安全点SafePoint.
如何让GC发生的时候让所有线程都跑到”安全点“停下来。方式有两种:
1. 抢先中断式(弃用):当发生GC时让所有线程都停下来,如果有线程没有到安全点,就让该线程继续跑到安全点
2. 主动式抢断:当线程执行GC需要中断时,不需要对线程进行操作,而是设置一个标志位,各线程注定去轮询这个标志位。标志位和安全点在同一个位置,发现标志位为真是就将自己这个线程中断挂起

主动式中断,避免了抢占式:中断—启动—中断的过程

安全点可以保证大部分线程停顿,但是当GC请求中断时线程并没有获取CPU执行权,线程无法响应JVM”跑到“安全点,但是JVM的GC不会等待线程获得CPU执行权再对他进行可达性分析或者回收。也就是说该线程现在在非安全点停止,并且GC对他进行了操作,这样的操作是不满足一致性的,当线程苏醒之后就会发生:线程在继续执行,GC也在操作该线程(这个过程对象的引用关系有可能会改变)

安全区就可以很好的解决这样的问题:安全区是指一段代码中不会改变引用关系,在这段代码区域发生GC中断请求是安全的,当线程进入安全区域之后会首先标识自己,在安全区中随便发生GC请求,当线程离开安全区的时候,会先检查是否完成了根节点枚举(或者说整个GC过程),完成的线程才能离开,没完成的完成了才能离开该区域

思考:javaGC回收时,sleep状态并不在安全区域的线程怎么办?
答:个人理解觉得安全区域是一个概念,也就是说当线程阻塞睡眠时,其实是可以认为安全的,毕竟线程没有工作,所以不会发生引用变化。用安全区域的概念来说,线程睡眠阻塞其实可以认为它是进入了安全区域,在睡眠阻塞标志了自己已经进入安全区域,那么GC其实可以不用去管这些线程了,就算GC(枚举根节点)的好好的,突然线程想唤醒工作,它发现已经标志了,必须等GC完成工作它才能继续执行


PART TWO: 垃圾收集器

CUP环境是多个或者单个CPU多核

收集算法时方法论,垃圾收集器就是内存回收的具体实现

1.Seral 收集器

单线程收集器,不只是一个线程去执行GC,更重要的体现在当他执行GC的时候必须暂停其他的所有工作线程,在用户看不见的情况下把正常的工作线程全部停掉。(Stop The World)

收集器的不断发展一致力于减少因内存回收而导致的停顿

单线程,常用于新生代复制,能与CMS配合

在这里插入图片描述
2.ParNew 收集器

是Seral 收集器的多线程版本,运行在Server模式下的首选新生代收集器,除了Seral 之外唯一能与CMS配合使用的垃圾收集器。实现了让垃圾收集线程和用户线程(基本上)同时工作。

垃圾收集器所说的并发和并行

  1. 并行:多条垃圾收集线程并行工作,但此时的用户线程仍处于等待状态
  2. 并发:指用户线程和垃圾收集线程同时执行(但不一定是并行,有可能是交替执行)

多线程,并行,新生代,能与CMS配合

3.Parallel Scavenge 收集器

新生代收集器,使用复制算法,parallel scavenge 收集器和其他的收集器关注的重点不同,CMS收集器关注的点是尽可能的缩短垃圾收集时用户线程停顿的时间,parallel scavenge 的关注点是达到一个可控制的吞吐量(提高CPU的使用效率),尽可能的减少垃圾收集线程的时间。

多线程,并行,新生代复制算法啊,关注点:吞吐量

工作线程停顿的时间越短越适合用户需要交互的情景

4.Parallel Old 收集器

在这里插入图片描述
parallel scavenge 的老年版

5.CMS 收集器

CMS 是以获取最短停顿时间为目标的收集器,目前的应用都十分中市响应时间,希望系统的停顿时间最短。CMS十分符合要求。
CMS 是基于“标记-清除”算法的收集器
收集过程:

  1. 初识标记 : 仅仅标记与GC Root 直接关联的对象,速度很快
  2. 并发标记:是GC Root Tracing 的过程
  3. 重新标记:为了修正并发标记期间因为用户线程继续运作而导致标记产生变动的那部分对象的标记记录,这个阶段的停顿比初识标记长,但远比并发标记时间短
  4. 并发清理:清理垃圾,回收内存
    初识标记和重新标记还是需要“Stop The World” ,并发标记和并发清除时,垃圾收集线程可以和用户线程一起工作

CMS 并发多线程收集,低停顿

在这里插入图片描述
CMS的缺点

  1. CMS 并发执行,对CPU资源比较敏感,并发阶段不会导致工作线程停止,但是垃圾回收线程也会占用一部分CPU资源,导致应用程序变慢,总的吞吐量会变低。CMS的默认垃圾回收线程(CPU数量+3)/4。 当CPU有4个时,垃圾回收线程会占用25% 的CPU资源。当CPU只有1个时,会导致用户线程的执行速度降低50%。对于这种情况,虚拟机提供了一种“增量式并发收集器”,在并发标记和并发清除的时候让垃圾回收线程和用户线程交替运行,减少垃圾回收独占CPU资源的时间,但是这样垃圾回收的时间会变长,但是“增量式收集器” 效果一般所以已被弃用。
  2. CMS 无法处理浮动垃圾,可能出现“Concurrent Model Failure” 失败而导致另一次 Full GC , 由于CMS的并发清理阶段 ,用户线程依然在运行,伴随程序的执行,就可能还会有新的垃圾产生,这部分垃圾被标记之后本次GC是无法清理的,只能等到下一次GC。这一部分垃圾称为“浮动垃圾”。
    也因为用户线程在垃圾线程工作的时候也要运行,所以还有留内存给用户线程运行。CMS不能像其他垃圾收集器那样等老年代完全被填满才进行收集,所以一般CMS 都有一个触发值:当老年代的内存被占用多少时触发垃圾回收。
    如果CMS预留的空间太小,无法满足用户线程的运行,导致出现“Concurrent Model Failure” 临时启用Serial 收集器对老年代进行回收,这样停顿的时间就会变长,效率变低。

    触发值:-XX:CMSInitiatingQccupancyFraction

  3. CMS 使用的是“标记-清除”算法,所以会有大量的内存碎片,会导致无法进行大空间分配,不得不提前触发下一次Full GC ,CMS为了解决这种情况专门设置了参数:-XX:UseCMSCompactAtFullCollection 默认为true ,用于当CMS顶不住要进行Full GC 之前先进行一次内存整理,但是因为内存整理是无法并发的所以需要停顿比较长的时间。

6.G1 收集器

面向服务端的垃圾收集器,在未来的目标是替换CMS。
特点:

  1. 并发与并行:G1 能充分利用多CPU多核环境下的硬件条件。使用多个CPU来缩短Stop-The-world 的时间,其他部分收集器需要停顿Java线程来完成GC 操作,但是G1 可以通过并发让Java线程继续执行

  2. 分代收集:G1能够独自管理整个Java堆,并且采用不同的方式去处理新创建的对象和已经存活了一段时间、熬过多次GC的旧对象以获取更好的收集效果。

  3. 空间整合:从整体上看是“标记-整理”算法,从局部(两个Region)之间是基于复制算法实现的。G1 的执行期间不会出现内存碎片

  4. 可预测的停顿:G1除了追求低停顿外,还能建立可预测的停顿时间模型。能让使用者明确指定在一个长度为M毫秒的时间段内,消耗在垃圾收集上的时间不得超过N毫秒。
    使用G1 时Java堆的分布布局和其他的垃圾收集器不同,他将整个Java堆分为一个个大小相等的独立区域Region,虽然仍旧保留老年代和新生代的概念,但是他们是一部分Region(不需要连续) 集合。
    G1 之所以能建立可预测的停顿的时间模型,是因为,G1 跟踪各个Region 里面的垃圾堆积的价值大小(回收可以获得的空间大小和所要消耗的时间),当有时间要求时,G1 会找到符合时间要求并且价值最高的Region进行垃圾回收

  5. G1收集器存在的问题:

    Region不可能是孤立的,分配在Region中的对象可以与Java堆中的任意对象发生引用关系。在采用可达性分析算法来判断对象是否存活时,得扫描整个Java堆才能保证准确性。其他收集器也存在这种问题(G1更加突出而已)。会导致Minor GC效率下降。

    G1收集器是如何解决上述问题的?

    采用Remembered Set来避免整堆扫描。G1中每个Region都有一个与之对应的Remembered Set,虚拟机发现程序在对Reference类型进行写操作时,会产生一个Write Barrier暂时中断写操作,检查Reference引用对象是否处于多个Region中(即检查老年代中是否引用了新生代中的对象),如果是,便通过CardTable把相关引用信息记录到被引用对象所属的Region的Remembered Set中。当进行内存回收时,在GC根节点的枚举范围中加入Remembered Set即可保证不对全堆进行扫描也不会有遗漏。

如果不计算维护 Remembered Set 的操作,G1收集器大致可分为如下步骤:

  1. 初始标记:仅标记GC Roots能直接到的对象,并且修改TAMS(Next Top at Mark Start)的值,让下一阶段用户程序并发运行时,能在正确可用的Region中创建新对象。(需要线程停顿,但耗时很短。)

  2. 并发标记:从GC Roots开始对堆中对象进行可达性分析,找出存活对象。(耗时较长,但可与用户程序并发执行)

  3. 最终标记:为了修正在并发标记期间因用户程序执行而导致标记产生变化的那一部分标记记录。且对象的变化记录在线程Remembered Set Logs里面,把Remembered Set Logs里面的数据合并到Remembered Set中。(需要线程停顿,但可并行执行。)

  4. 筛选回收:对各个Region的回收价值和成本进行排序,根据用户所期望的GC停顿时间来制定回收计划。(可并发执行,但是停顿的收集效率更高)
    在这里插入图片描述

G1 和CMS 相比较的优势在于没有空间碎片和停顿时间可预测模型

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
为什么要学JVM1、一切JAVA代码都运行在JVM之上,只有深入理解虚拟机才能写出更强大的代码,解决更深层次的问题。2、JVM是迈向高级工程师、架构师的必备技能,也是高薪、高职位的不二选择。3、同时,JVM又是各大软件公司笔试、面试的重之重,据统计,头部的30家互利网公司,均将JVM作为笔试面试的内容之一。4、JVM内容庞大、并且复杂难学,通过视频学习是最快速的学习手段。课程介绍本课程包含11个大章节,总计102课时,无论是笔试、面试,还是日常工作,可以让您游刃有余。第1章 基础入门,从JVM是什么开始讲起,理解JDK、JRE、JVM的关系,java的编译流程和执行流程,让您轻松入门。第2章 字节码文件,深入剖析字节码文件的全部组成结构,以及javap和jbe可视化反解析工具的使用。第3章 类的加载、解释、编译,本章节带你深入理解类加载的分类、范围、双亲委托策略,自己手写类加载,理解字节码解释、即时编译、混合模式、热代码检测、分层编译等核心知识。第4章 内存模型,本章节涵盖JVM内存模型的全部内容,程序计数、虚拟机栈、本地方法栈、方法区、永久代、元空间等全部内容。第5章 对象模型,本章节带你深入理解对象的创建过程、内存分配的方法、让你不再稀里糊涂。第6章 GC基础,本章节是垃圾回收的入门章节,带你了解GC回收的标准是什么,什么是可达性分析、安全安全区,四种引用类型的使用和区别等等。第7章 GC算法与收集,本章节是垃圾回收的重,掌握各种垃圾回收算法,分代收集策略,7种垃圾回收的原理和使用,垃圾回收的组合及分代收集等。第8章 GC日志详解,各种垃圾回收的日志都是不同的,怎么样读懂各种垃圾回收日志就是本章节的内容。第9章 性能监控与故障排除,本章节实战学习jcmd、jmx、jconsul、jvisualvm、JMC、jps、jstatd、jmap、jstack、jinfo、jprofile、jhat总计12种性能监控和故障排查工具的使用。第10章 阿里巴巴Arthas在线诊断工具,这是一个特别小惊喜,教您怎样使用当前最火热的arthas调优工具,在线诊断各种JVM问题。第11章 故障排除,本章会使用实际案例讲解单故障、高并发和垃圾回收导致的CPU过高的问题,怎样排查和解决它们。课程资料课程附带配套项目源码2个159页高清PDF理论篇课件1份89页高清PDF实战篇课件1份Unsafe源码PDF课件1份class_stats字段说明PDF文件1份jcmd Thread.print解析说明文件1份JProfiler内存工具说明文件1份字节码可视化解析工具1份GC日志可视化工具1份命令行工具cmder 1份学习方法理论篇部分推荐每天学习2课时,可以在公交地铁上用手机进行学习。实战篇部分推荐对照视频,使用配套源码,一边练习一遍学习。课程内容较多,不要一次性学太多,而是要循序渐进,坚持学习。      

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值