昨天总结了GC之前要做的事情,今天介绍一下主流的GC算法。

先介绍一下几个名词:

Stop The World(STW):JVM进行GC的时候总不能一边清理垃圾一边制造垃圾把,那么垃圾鉴定的准确性根本无法得到保证,所以需要将服务全部停掉那么一瞬间;

Yong GC、Minor GC:年轻代区域的GC,所有的年轻代GC都会触发STW;

Old GC、Major GC:老年代区域的GC,只有串行部分会触发STW;

Full GC:主要针对老年代区域而言的串行GC,会触发STW。

首先说一下年龄分代收集算法,根据对象的存活周期,将堆区分为年轻代(新生代)和老年代。顾名思义,刚生成的对象放入年轻代,勤用勤收集,对象成功经历几轮GC后仍存活下来,便将它移入到老年代中去,如果老年代也满了,那么会触发Full GC。如果你是JVM设计者,你会怎么分配年轻代和老年代的比重呢?老年代收集效率差,存活率高,轻易不要移动这里的对象,如果老年代空间不充足,便会频繁触发Full GC,得不偿失;如果老年代分配过多也不好,对象全都跑到老年代了,长时间不触发清理操作会造成过于碎片化,严重导致空有内存却无法分配的现象。因此堆区应该为老年代和年轻代分配合适的比例,一般为4:1(调优参数:-XX:NewRatio=4)

实际上大多数的JVM都是以年龄分代算法为基础,将堆区划分成独立的两个区域,然后再结合其他的GC算法分开进行GC,从而更高效。

最先提出来的是标记清除法:先将堆区的需要回收的对象标记下来,然后统一回收。它会产生两个问题,首先是效率低下,标记和清理过程的效率都是很低的;然后是碎片问题,剩余的存活的对象分散各处,造成堆区碎片化,不方便为大对象分配内存。

针对上面两个问题,提出了复制算法,把堆区分为一个eden区域和两个小的survivor区域,当需要申请内存时,JVM会在较大的eden区域为其分配空间,当eden区域无法为新对象提供内存时,JVM将其中一个survivor空间和eden空间中存活的对象移到另一个survivor中,然后清空eden和之前使用过的survivor,按此循环,也就是说,总有一个survivor区域是留空的,用来存放其余二者存活的对象。

将上面两个方法对比来看,复制算法更适合用来处理存活率低的内存区域,也就意味着复制量小,更高效,显而易见,它是一个年轻代算法;相对而言,如果用标记清除法处理年轻代,使这片空间过于碎片化,当eden为较大对象分配空间时便会很乏力(实际上大对象或大数组是直接在老年代分配的),而且年轻代应该像他的名字一样高效、快速GC,该算法的标记和清除效率并不高,因此标记清除法更应该拿来处理老年代。

针对标记清除法的碎片化问题以及老年代的特点,有人又提出了一个改进措施,标记整理法,它的思想是:让存活的对象向一端移动,然后从边界处将另一侧所有空间直接清理掉。


前面提到了标记,内存中这么多引用变量,JVM如何寻找它是对象引用类型呢?其实,JVM使用了一组OopMap的数据结构来存放引用类型,在JIT编译和类加载的时候记录下来那些位置是引用,这样GC的时候,JVM就可以快速且准确的完成GC Roots的枚举了。

到这里,又引出了另外一个问题,变量、对象间的引用关系是一直在变化的,JVM不可能监听每一条指令,代价太大。所以引出了安全点这个概念,如果在安全点位置上我们对OopMap进行校准的话,那么JVM是可以在这个位置进行GC的,此时STW之后的引用类型是准确的。那么什么位置可以作为安全点呢?1、所有指令的末尾均可添加 2、方法调用、循环回跳之前等可添加; 它的选定是依据“程序在此处是否会长时间执行”为标准的。

对于多线程的程序,STW的时候是需要全部暂停的,但我们并不能保证多个线程正在执行的指令处是否有安全点,上一段已经说明只有安全点处才可以安全准确的GC。这里有两种解决方案:

1、抢先式中断:JVM觉得可以GC了,那就先STW,然后检查所有线程是否在安全点上,不在的话就让它继续执行;很少JVM会采用这种方式

2、主动式中断:在安全点上加一个轮询的标志,在需要GC时,将该标志设为中断值,已经在安全点上的线程便会轮询等待,未在安全点上的线程读取不到这个标志会继续执行

如果一个线程没有分配到时间片,线程出于sleep或blocked状态如何处理呢?JVM不可能等到它分配时间片之后在GC把。因此提出了安全区域这个概念,只有这段指令不会导致引用变化的片段才可以作为安全区域使用,在GC时JVM会忽视掉处于安全区域的线程,在这个区域内的任何地方开始GC都是安全的。当线程执行到安全区域的代码时,首先标识自己进入了安全区域。如果它要走出安全区域,需要先检查JVM是否处于GC状态且是否已经完成了根节点枚举,如果满足了根节点枚举或不在GC状态,它就可以走出来继续执行代码,否则他必须得等待知道收到信号为止。

JVM之GC(二)的更多相关文章

  1. 深入JVM系列(二)之GC机制、收集器与GC调优

    一.回想JVM内存分配 须要了解很多其它内存模式与内存分配的,请看 深入JVM系列(一)之内存模型与内存分配 1.1.内存分配: 1.对象优先在EDEN分配 2.大对象直接进入老年代  3.长期存活的 ...

  2. 深入JVM系列(二)之GC机制、收集器与GC调优(转)

    一.回顾JVM内存分配   需要了解更多内存模式与内存分配的,请看 深入JVM系列(一)之内存模型与内存分配 1.1.内存分配: 1.对象优先在EDEN分配2.大对象直接进入老年代 3.长期存活的对象 ...

  3. JVM的GC概述

    JVM的GC概述 GC即垃圾回收,是指jvm用于释放那些不再使用的对象所占用的内存.在充分理解了垃圾收集算法和执行过程后,才能有效的优化它的性能. 有些垃圾收集专用于特殊的应用程序.比如,实时应用程序 ...

  4. JVM 系列(二)内存模型

    02 JVM 系列(二)内存模型 一.JVM 内存区域 JVM 会将 Java 进程所管理的内存划分为若干不同的数据区域.这些区域有各自的用途.创建/销毁时间: 一. 线程私有区域 线程私有数据区域生 ...

  5. JVM之GC算法的实现(垃圾回收器)

    上一节:<JVM之GC算法> 知道GC算法的理论基础,我们来看看具体的实现.只有落地的理论,才是真理. 一.JVM垃圾回收器的结构 JVM虚拟机规范对垃圾收集器应该如何实现没有规定,因为没 ...

  6. 聊一聊 JVM 的 GC

    原文链接:https://www.changxuan.top/?p=1457 引言 JVM 中的 GC 在技术博客中应该算是个老生常谈的话题,网络上也存在着许多质量参差不齐的文章,可以看出来大都是&q ...

  7. Linux使用jstat命令查看jvm的GC情况

    Linux使用jstat命令查看jvm的GC情况 http://www.open-open.com/lib/view/open1390916852007.html http://www.aiuxian ...

  8. java之jvm学习笔记二(类装载器的体系结构)

    java的class只在需要的时候才内转载入内存,并由java虚拟机的执行引擎来执行,而执行引擎从总的来说主要的执行方式分为四种, 第一种,一次性解释代码,也就是当字节码转载到内存后,每次需要都会重新 ...

  9. poptest老李谈jvm的GC

    poptest老李谈jvm的GC   poptest是国内唯一一家培养测试开发工程师的培训机构,以学员能胜任自动化测试,性能测试,测试工具开发等工作为目标.如果对课程感兴趣,请大家咨询qq:90882 ...

随机推荐

  1. gensim的word2vec如何得出词向量(python)

    首先需要具备gensim包,然后需要一个语料库用来训练,这里用到的是skip-gram或CBOW方法,具体细节可以去查查相关资料,这两种方法大致上就是把意思相近的词映射到词空间中相近的位置. 语料库t ...

  2. ORACLE内部操作

    当执行查询时,ORACLE采用了内部的操作. 下表显示了几种重要的内部操作. ORACLE Clause 内部操作 ORDER BY SORT ORDER BY UNION UNION-ALL MIN ...

  3. springmvc url处理映射的三种方式:

    一.SpringMVC简介 SpringMVC是一种基于Spring实现了Web MVC设计模式的请求驱动类型的轻量级Web框架,使用了MVC架构模式的思想,将web层进行职责解耦,并管理应用所需对象 ...

  4. springmvc 过滤器和拦截器

     1. 拦截器: interceptor 过滤器(filter)与拦截器(intercepter)相同点:1) 都可以拦截请求,过滤请求2) 都是应用了过滤器(责任链)设计模式 2.区别: 1) fi ...

  5. 洛谷P1595 信封问题 题解 错排问题

    作者:zifeiy 标签:排列组合,错排问题 题目链接:https://www.luogu.org/problem/P1595 题目描述:某人写了n封信和n个信封,如果所有的信都装错了信封.求所有信都 ...

  6. SQL2008 R2安装完成后开启services服务指引和 sa账号启用、数据类型

  7. 【a403】遍历树问题

    Time Limit: 1 second Memory Limit: 32 MB [问题描述] 我们都很熟悉二叉树的前序.中序.后序遍历,在数据结构中常提出这样的问题:已知一棵二叉树的前序和中序遍历, ...

  8. Linux创建用户、设置密码、修改用户、删除用户命令

    与大家分享下Linux系统中创建用户.设置密码.修改用户.删除用户的命令,希望对你有所帮助. useradd testuser  创建用户testuserpasswd testuser  给已创建的用 ...

  9. css 百分比继承关系的探讨

    引入:近日在回顾css基础的时候发现了一个有趣的问题,就是css在继承百分比类属性的时候是继承百分比后再根据父级宽高计算,还是继承父级根据百分比计算过后的绝对值.下面举一个简单的例子来描述这一个问题, ...

  10. 关于Android studio Haxm加速器安装

    首先,在SDK manager中要安装如下选项 安装后,在启动虚拟机时如果提示你没有Install Haxm,在目录sdk\extras\intel\Hardware_Accelerated_Exec ...