JVM GC系列 — GC算法
一.前言
从本篇文章开始,将开始一个新的系列JVM。JVM是一个非常庞大且复制的技术体系,但是对于程序猿的升级,走向更高阶所必要经历的,曾经也下决心要好好学习一番,然而毅力不足都中途放弃。
GC的作用就是回收垃圾,但是要做到做点必须要解决两个问题:
- 如何确定哪些是垃圾
- 怎样回收垃圾
这两个问题可谓是GC的核心,本篇文章将从算法角度学习GC是怎样解决这两个问题。
### 二.如何确定哪些是垃圾
1.引用计数法
在Java应用中,可被回收的对象必然是无用对象,即没有其他对象引用它或者其脱离了应用的中的对象整体:
如上图,蓝色标记的对象之间相互引用,都是存活对象,GC不应该回收。而红色标记的对象,已经没有任何对象引用它,GC应该回收它。
从以上可以确定,GC首先应该回收没有任何引用指向其的对象。如何表达没有任何引用?
为每个对象维护一个计数器,该计数器表示指向其的引用。当没有引用其时,则计数器应该为0,GC则应该回收。这种算法被称为引用计数法。
如上图,当计数器为0时,表示该对象已经没有任何引用,可被垃圾收集器回收。该算法实现非常简单,且性能较佳,但是存在局限性。
2.引用计数法的局限性
引用计数法固然简单易于理解,但是它无法解决相互引用的问题。当两个以上的对象之间相互引用,但是它们已经脱离整个Java对象的整体时,引用计数法便无法表达出它们是可回收对象:
如上图,当两个红色的标记的对象相互引用,此外没有任何对象引用它们,显然它们是可回收对象。但是引用计数法会造成无法被回收。
假如有以下代码:
void referenceCount() {
...
A a = new A();
B b = new B(a);
a.setB(b);
...
}
A和B之间相互引用,但是此外没有任何对象引用A和B,那么当线程运行退出referenceCount方法时,A和B依然不能被回收。
3.可达性分析算法
由于引用计数法的局限性,显然它不适合作为JVM中定位可回收对象的算法。实际上再JVM中使用另一种方式表示对象是否可回收 — 可达性分析算法。
可达性分析算法:能从GC Roots找到一条到该对象的引用链路,则该对象就是存活对象,如何找不到,则该对象就是可回收对象。
这里首先要明白什么是GC Roots:
- 栈(栈帧中的本地变量表)中引用的对象
- 方法区中的静态成员
- 方法区中的常量引用的对象
- 本地方法栈中JNI(一般说的Native方法)引用的对象
Note:
简而言之,可达性分析算法就是根搜索算法,类似于树结构的搜索。其中GC Roots就是根,其他对象就是树上的节点。在根和节点之间寻找路径。
从图中可以看出,可达性分析算法能够解决相互引用的问题。从GC Roots开始到对象之间存在一条引用链路,则就是存活对象,反之即是死亡对象。
### 三.怎样回收垃圾
通过以上的可达性分析算法,GC能够找到堆区中的可回收对象,但是具体怎样回收才能具有更高的效率呢?在JVM中存在以下几种回收算法:
- 标记清除
- 复制
- 标记整理
以上三种算法都各有利弊,下面逐一介绍。
1.标记清除算法
顾名思义,该算法分为两个阶段,先标记出可回收对象,然后再清除这些对象。
将堆区看成以上连输的方块片段,红色代表没有GC Roots引用的对象,蓝色代表有引用。
标记清除算法,首先针对堆区对象进行标记,标记出没有GC Root是对象引用的对象。然后再将没有GC Roots引用的对象清除。
该算法的效率较高,只需要标记然后清除即可。但是从图中也可以看出问题所在,在清除后,会造成大量的不连续的内存碎片,当有大对象分配时,将又会触发GC,从而影响性能。
2.复制算法
为了解决标记清除算法的导致的内存碎片问题,复制算法因此而生。复制算法的思想是将内存分为两块,每次只使用其中一块,回收时将存活的对象复制到另一块中,然后将使用的那块完全清除,再使用新的复制那块。
经过复制算法后,不会再产生断断续续的内存碎片。每次垃圾回收之后,都能得到连续的大片内存。但是又产生了新的问题,内存是昂贵资源,将其分成两块,每次只使用其中一块,造成了资源浪费。但是实际中,对象基本上都是朝生夕死,能存活的对象少之又少,所以实际中一般不会按照1:1的比例分块。在Hostspot的年轻代默认按照8:1的进行划分,即Eden:Survivor=8:1。
3.标记整理算法
为了既解决标记清除算法带来的内存碎片问题,又能很好解决复制算法的内存牺牲问题。又出现标记整理算法。它类似标记清除,但是又增加了一个整理过程。即将存活对象往一端移动,整理内存碎片,形成连续内存。
通过标记清理,能够将回收垃圾对象,释放内存。通过整理压缩,能够形成连续内存,解决内存碎片。
虽然标记整理算法解决了复制算法和标记清除算法带来的问题,但是整理压缩也是耗费性能,降低效率。
4.分代算法
以上的GC回收算法都各有利弊,实际使用中,根据内存区域的划分以及其特点,HotSpot不单一采用以上的算法,而是根据堆区不同分代,分别采用以上算法,这种算法被称为分代算法。
由于Java对象具有朝生夕死的特点,堆区一般划分为新生代(年轻代)和老年代(年老代)。新生代对象生存周期短暂,老年代对象生成周期较长:
- 新生代对象存活周期短,每次只有少量对象存活,使用复制算法比较适宜。所以HotSpot中将新生代分为Eden和Survivor区域。
- 老年代对象存活时间长,每次GC后,大部分对象都存活。所以使用标记整理算法。
### 总结
本篇文章主要介绍GC中两个核心问题,第一:GC如何确定哪些对象是可回收的,在HotSpot中使用从GC Roots开始的可达性分析算法,定位对象是否存活。第二:在确定对象的存活与否后,采用何种策略回收对象。商业虚拟机中多数采用分代算法解决该问题。在了解了GC回收算法后,下篇文章再围绕这些算法学习HotSpot中的有哪些具体实现。
JVM GC系列 — GC算法的更多相关文章
- JVM GC系列 — GC收集器
一.前言 前文学习了各种GC回收算法,掌握了GC回收的原理,但是真正的GC实现却尤为复杂,本篇文章将主要介绍各种GC收集器. 目前主流的HotSpot VM支持多种虚拟机,这些虚拟机也体现了GC的发展 ...
- JVM内存管理------GC算法精解(五分钟教你终极算法---分代搜集算法)
引言 何为终极算法? 其实就是现在的JVM采用的算法,并非真正的终极.说不定若干年以后,还会有新的终极算法,而且几乎是一定会有,因为LZ相信高人们的能力. 那么分代搜集算法是怎么处理GC的呢? 对象分 ...
- JVM学习之GC常用算法
出处:博客园左潇龙的技术博客--http://www.cnblogs.com/zuoxiaolong,多谢分享 GC策略解决了哪些问题? 既然是要进行自动GC,那必然会有相应的策略,而这些策略解决了哪 ...
- JVM基础系列第14讲:JVM参数之GC日志配置
说到 Java 虚拟机,不得不提的就是 Java 虚拟机的 GC(Garbage Collection)日志.而对于 GC 日志,我们不仅要学会看懂,而且要学会如何设置对应的 GC 日志参数.今天就让 ...
- JVM中的GC算法,JVM参数,垃圾收集器分类
一.在JVM中什么是垃圾?如何判断一个对象是否可被回收?哪些对象可以作为GC Roots的根 垃圾就是在内存中已经不再被使用到的空间就是垃圾. 1.引用计数法: 内部使用一个计数器,当有对象被引用+1 ...
- 【JVM第八篇--垃圾回收】GC和GC算法
写在前面的话:本文是在观看尚硅谷JVM教程后,整理的学习笔记.其观看地址如下:尚硅谷2020最新版宋红康JVM教程 1.垃圾 1.1.什么是垃圾 垃圾(Garbage)在Java语言中是指在运行程序中 ...
- JVM学习笔记——GC算法
GC 算法 GC 即 Garbage Collection 垃圾回收.JVM 中的 GC 99%发生在堆中,而 Java 堆中采用的垃圾回收机制为分代收集算法.即将堆分为新生代和老年代,根据不同的区域 ...
- JVM组成、GC回收机制、算法、JVM常见启动参数、JAVA出现OOM,如何解决、tomcat优化方法
JVM组成.GC回收机制.算法.JVM常见启动参数.JAVA出现OOM,如何解决.tomcat优化方法
- JVM架构和GC垃圾回收机制
深入理解系列之JDK8下JVM虚拟机(1)——JVM内存组成 https://blog.csdn.net/u011552404/article/details/80306316 JVM架构和GC垃圾回 ...
随机推荐
- 【Golang基础】defer执行顺序
defer 执行顺序类似栈的先入后出原则(FILO) 一个defer引发的小坑:打开文件,读取内容,删除文件 // 原始问题代码 func testFun(){ // 打开文件 file, ...
- pycharm中全局搜索ctrl+shift+F快捷键无反应原因和解决
全局搜索快捷键无反应原因:搜狗输入法占用的ctrl+shift+F快捷键,简繁切换的快捷键.在搜狗输入法中将此项取消.
- import com.sun.org.apache.xml.internal.security.utils.Base64问题
———————————————— 版权声明:本文为CSDN博主「荚小白」的原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接及本声明.原文链接:https://blog.csd ...
- 一文掌握 Lambda 表达式
本文将介绍 Java 8 新增的 Lambda 表达式,包括 Lambda 表达式的常见用法以及方法引用的用法,并对 Lambda 表达式的原理进行分析,最后对 Lambda 表达式的优缺点进行一个总 ...
- 计算机组成原理——DMA存取方式
DMA(Direct Memory Access)直接存储器存取 高速大容量存储器和主存之间交换时,若采用程序直接传送或程序中断传送的方式,则会有如下问题发生. 1)采用程序直接传送,主机工作效 ...
- Spring常用注解式开发
1.组件注册@Configuration.@Bean给容器中注册组件. 注解,@Configuration告诉Spring这是一个配置类,相当于bean.xml配置文件. 注解,@Bean给Sprin ...
- thymeleaf Exception processing template "xxx": Exception parsing document: template="xxx", line 6 - column 3报错解决的几种方法
我是在SpringBoot项目使用Thymeleaf作为模板引擎时报的错误 controller代码非常简单,如下所示: @RequestMapping("/abc") publi ...
- PHP mysqli_stmt_bind_param MySQLi 函数
定义和用法 mysqli_stmt_bind_param - 将变量绑定到准备好的语句作为参数 版本支持 PHP4 PHP5 PHP7 不支持 支持 支持 语法 mysqli_stmt_bind_pa ...
- CAD简易口诀,保你一天就记住!零基础也能轻松学!CAD制图宝典!
如何才能快速的学习CAD制图呢?不仅仅需要多练习,CAD口诀也是不能错过的哦!实用干货这一个就够了快点收藏起来! 1.创建直线的快捷方式是L+空格 2.创建圆的快捷方式是C+空格 3.创建圆弧的快捷方 ...
- SpringCloud(五):断路器(Hystrix)和hystrixdashboard图实现链路追踪
第一:关于服务调用和熔断安全: ribbon和Feign: 1. 相当于nigx+doubbe,微服务间的服务调用,API网关的请求转发等内容2. Feign整合了Ribbon和Hystrix Hy ...