JVM之GC(二)
昨天总结了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(二)的更多相关文章
- 深入JVM系列(二)之GC机制、收集器与GC调优
一.回想JVM内存分配 须要了解很多其它内存模式与内存分配的,请看 深入JVM系列(一)之内存模型与内存分配 1.1.内存分配: 1.对象优先在EDEN分配 2.大对象直接进入老年代 3.长期存活的 ...
- 深入JVM系列(二)之GC机制、收集器与GC调优(转)
一.回顾JVM内存分配 需要了解更多内存模式与内存分配的,请看 深入JVM系列(一)之内存模型与内存分配 1.1.内存分配: 1.对象优先在EDEN分配2.大对象直接进入老年代 3.长期存活的对象 ...
- JVM的GC概述
JVM的GC概述 GC即垃圾回收,是指jvm用于释放那些不再使用的对象所占用的内存.在充分理解了垃圾收集算法和执行过程后,才能有效的优化它的性能. 有些垃圾收集专用于特殊的应用程序.比如,实时应用程序 ...
- JVM 系列(二)内存模型
02 JVM 系列(二)内存模型 一.JVM 内存区域 JVM 会将 Java 进程所管理的内存划分为若干不同的数据区域.这些区域有各自的用途.创建/销毁时间: 一. 线程私有区域 线程私有数据区域生 ...
- JVM之GC算法的实现(垃圾回收器)
上一节:<JVM之GC算法> 知道GC算法的理论基础,我们来看看具体的实现.只有落地的理论,才是真理. 一.JVM垃圾回收器的结构 JVM虚拟机规范对垃圾收集器应该如何实现没有规定,因为没 ...
- 聊一聊 JVM 的 GC
原文链接:https://www.changxuan.top/?p=1457 引言 JVM 中的 GC 在技术博客中应该算是个老生常谈的话题,网络上也存在着许多质量参差不齐的文章,可以看出来大都是&q ...
- Linux使用jstat命令查看jvm的GC情况
Linux使用jstat命令查看jvm的GC情况 http://www.open-open.com/lib/view/open1390916852007.html http://www.aiuxian ...
- java之jvm学习笔记二(类装载器的体系结构)
java的class只在需要的时候才内转载入内存,并由java虚拟机的执行引擎来执行,而执行引擎从总的来说主要的执行方式分为四种, 第一种,一次性解释代码,也就是当字节码转载到内存后,每次需要都会重新 ...
- poptest老李谈jvm的GC
poptest老李谈jvm的GC poptest是国内唯一一家培养测试开发工程师的培训机构,以学员能胜任自动化测试,性能测试,测试工具开发等工作为目标.如果对课程感兴趣,请大家咨询qq:90882 ...
随机推荐
- Python--day67--Django的路由系统
原文:https://www.cnblogs.com/liwenzhou/articles/8271147.html Django的路由系统 Django 1.11版本 URLConf官方文档 URL ...
- HDU 2602Bone Collector 01背包问题
题意:给出一个t代表有t组数据,然后给出n,n代表有n种石头,v代表旅行者的背包容量,然后给出n种石头的价值和容量大小,求能带走的最大价值 思路:01背包问题,每种石头只有拿与不拿两种状态.(其实我是 ...
- C++继承方式
C++的继承方式有三种,分别为: 公有继承:public 私有继承:private 保护继承:protected 定义格式为: class<派生类名>:<继承方式><基类 ...
- H3C ACL包过滤显示与调试
- java 集合类 & 容器
为什么出现集合类? 面向对象语言对事物的体现都是以对象的形式,所以为了方便对多个对象的操作,就要对对象进行存储,集合就是存储对象最常用的一种方式. 数组和集合类同是容器,有何不同? 数组虽然也可以存储 ...
- siblings() 获得匹配集合中每个元素的同胞
定义和用法 siblings() 获得匹配集合中每个元素的同胞,通过选择器进行筛选是可选的. 如果给定一个表示 DOM 元素集合的 jQuery 对象,.siblings() 方法允许我们在 DOM ...
- 【t085】Sramoc问题
Time Limit: 1 second Memory Limit: 128 MB [问题描述] Sramoc(K,M)表示用数字0,1,2,...,K-1组成的自然数中能被M整除的最小数.给定K,M ...
- #干货#小微信贷风控中类IPC模式和集中审批模式
浅析小微信贷风控中类IPC模式和集中审批模式 席占斌 常言道瑕不掩瑜,反过来讲瑜自然也不能掩瑕,看问题需要客观公正辩证. 在小微信贷中,风控模式依旧是核心,目前比较流行和占比较大的风控模式有很经典的I ...
- python进阶之异常处理
异常处理 在代码运行时,会因为各种原因出现bug,而程序遇到bug就会中断运行,而在日常生产中程序是要长时间运行不能随意中断的.因此就需要我们提前做好异常处理. 异常 print(x) # 一般报错就 ...
- MySQL之Field‘***’doesn’t have a default value错误解决办法
这篇文章主要介绍了MySQL之Field‘***’doesn’t have a default value错误解决办法,需要的朋友可以参考下 今天,中国博客联盟有博友反馈,zgboke.com无法提交 ...