【JAVA进阶架构师指南】之四:垃圾回收GC
前言
在【JAVA进阶架构师指南】系列二和三中,我们了解了JVM的内存模型以及类加载机制,其中在内存模型中,我们说到,从线程角度来说,JVM分为线程私有的区域(虚拟机栈/本地方法栈/程序计数器)和线程公有区域(方法区和java堆),其中线程私有区域内存随着线程的结束而跟着被回收,GC主要关注的是堆和方法区这部分的内存.
GC回收算法
GC如何确定哪些对象需要回收呢?一般而言,有两种算法:引用计数算法和可达性分析算法.
引用计数算法
为每个对象都持有一个引用计数器,初试状态为0,该对象每次被引用就加一,否则就减一,因此当GC进行垃圾回收的时候,判断如果该引用计数器=0则进行回收,否则不进行回收,显而易见,引用计数算法的缺点就是不能解决循环依赖的问题,假如对象A引用对象B,对象B引用对象C,对象C引用对象A,循环依赖导致ABC三个对象都不能被回收.因此引出了可达性分析算法.
可达性分析算法
所谓可达性分析算法,就是通过一系列名为"GC Roots"的对象作为起始点,从这些节点开始向下搜索,搜索所走过的路径称为引用链(Reference Chain),当一个对象到GC Roots没有任何引用链相连时,则证明此对象是可以被回收的,反之则不可被回收,在JAVA中,可被作为"GC Roots"的对象包括如下几种:
a.虚拟机栈(栈桢中的本地变量表)中的引用的对象
b.方法区中的类静态属性引用的对象
c.方法区中的常量引用的对象
d.本地方法栈中JNI的引用的对象
java语言对象引用类型
无论是引用计数算法还是可达性分析算法,都涉及到对象的引用,在Java中,引用分为强引用、软引用、弱引用、虚引用(幽灵引用)4种,这四种引用强度依次逐渐减弱.所谓强引用,就是我们平时最常用的new一个新对象,比如:
Object object = new Object();
强引用的对象永远不会被GC回收,即使在内存不足的情况下,JVM宁愿抛出OutOfMemory错误也不会回收这种对象,因此,我们看许多优秀框架的源码的时候,经常会看到如下代码:

后面有注释//help gc, 将对象置为null,帮助GC进行垃圾回收,这里就是消除强引用,让无用对象的内存能被顺利回收.有兴趣的童鞋可以多多翻看优秀框架的源码,比如JDK/Spring中肯定会有大量这样的写法,足见这些源码作者的态度之严谨,编程功力之深厚,值得我们学习!
而软引用、弱引用、虚引用这几类在JDK中都有对应的实现,分别对应SoftReference/WeakReference/PhantomReference,由于博客篇幅有限,不能所有知识点都讲得很详细,只能告诉童鞋们有这些知识点,有兴趣的童鞋可以自己下去学习了解.
GC回收策略
讲完了GC如何确定哪些对象需要回收之后,我们再来看看GC进行垃圾回收有哪些策略,一般而言,有三种:标记清除算法/复制算法/标记整理算法.
1.标记清除算法
标记清除算法是最基础的回收算法,分为标记和清除两个部分:首先标记出所有需要回收的对象,这一过程在可达性分析过程中进行.在标记完之后统一回收所有被标记的对象: 
这种算法的缺点很明显,就是会产生大量不连续的内存碎片,导致经常无法分配出较大的内存,从而不得不经常触发垃圾回收.
2.复制算法
既然不能回收出连续的内存空间,那就从一开始就把内存划分为两个区,平时只用一个区域,当其中一个区域内存满了,触发GC时,找出无需回收的对象,将它们全部转移到另一块未使用的区域,并且整理到一起使之连续,如此循环,这就是复制算法:

复制算法改善了标记清楚算法中内存碎片不连续的缺点,但是它的缺点也很明显,内存利用率不高,每次只能使用50%的内存.
3.标记整理算法
既然复制算法每次只能使用一半的内存,内存使用率不高,那就再继续优化,还是和标记清楚算法一样使用全部区域的内存,不同于标记清除算法的是进行垃圾回收时,确认无需回收的对象,然后将这些对象进行整理后向一端移动:

标记整理算法的优点在于内存使用率更充分,并且不会产生大量内存碎片.
堆(Heap)中的回收算法
java堆采用分代搜集来进行垃圾回收.首先明确一点,堆中为什么要进行分代?或者说,java堆为什么要使用分代收集算法来进行垃圾回收?因为据权威统计,80%以上的对象都是朝生夕死,即这些对象随着方法的执行完毕而不再使用,可以被回收,而剩余的20%左右的对象是还需要继续被使用,无法回收的,因此,JDK根据对象的这种特点进行分代收集,一句话概括就是对象的生命周期不同.
所谓分代收集,就是把java堆分为新生代和老年代,老年代采用标记整理算法,而新生代采用复制算法,其中将新生代划分为伊甸园区(Eden)和幸存区(Survivor)S0以及S1(有的也称之为Survivor from和Survivor to),默认情况下其比例为8:1:1,而整个新生代和老年代的比例为1:2(即新生代占整个堆区1/3,而老年代占2/3):

至于新生代和老年代的详细工作流程,就不再赘述,网上这种博客太多了.需要注意的是,发生在新生代的GC称之为Minor GC或者 Young GC,而发生在老年代的GC称之为Full GC或者Major GC,一般而言,Full GC的效率会比Minor GC低十倍以上!
读完本篇文章,我相信童鞋们应该对JVM垃圾回收有了一定的了解,下一篇文章,让我们来学习一下JVM篇最后一个知识点,也是最重要的知识点---JVM性能调优,敬请期待!
如果觉得博主写的不错,欢迎关注博主微信公众号,博主会不定期分享技术干货!

本文由博客一文多发平台 OpenWrite 发布!
【JAVA进阶架构师指南】之四:垃圾回收GC的更多相关文章
- 【JAVA进阶架构师指南】之五:JVM性能调优
前言 首先给大家说声对不起,最近属实太忙了,白天上班,晚上加班,回家还要收拾家里,基本每天做完所有事儿都是凌晨一两点了,没有精力再搞其他的了. 好了,进入正题,让我们来聊聊JVM篇最后一个章节 ...
- 【JAVA进阶架构师指南】之一:如何进行架构设计
前言 本博客是长篇系列博客,旨在帮助想提升自己,突破技术瓶颈,但又苦于不知道如何进行系统学习从而提升自己的童鞋.笔者假设读者具有3-5年开发经验,java基础扎实,想突破自己的技术瓶颈,成为一位优 ...
- 【JAVA进阶架构师指南】之二:JVM篇
前言 谈到JAVA,就不得不提JVM---JAVA程序员绕不开的话题.也许有童鞋会说,我不懂JVM,但是我一样可以写出JAVA代码,我相信说这种话的童鞋,往往是只有1-3年的初级开发人员,对JAV ...
- 【JAVA进阶架构师指南】之三:深入了解类加载机制
前言 在上一篇文章中,我们知道了JVM的内存划分,其中在说到方法区的时候说到方法区中存放的信息包括[已被JVM加载的类信息,常量,静态变量,即时编译的代码等],整个方法区其实就和类加载有关. 类加 ...
- Java进阶之内存管理与垃圾回收
Java是在JVM所虚拟出的内存环境中运行的.内存分为栈(stack)和堆(heap)两部分.我们将分别考察这两个区域. 栈 在Java中,JVM中的栈记录了线程的方法调用.每个线程拥有一个栈.在某个 ...
- Java互联网架构师系统进阶课程学习 (4)【享学】
Java互联网架构师系统进阶课程学习 (4)[享学] 4.显式锁和AQS 显式锁 Lock接口和核心方法 Lock接口和synchronized的比较 synchronized 代码简洁,Lock ...
- 15套java互联网架构师、高并发、集群、负载均衡、高可用、数据库设计、缓存、性能优化、大型分布式 项目实战视频教程
* { font-family: "Microsoft YaHei" !important } h1 { color: #FF0 } 15套java架构师.集群.高可用.高可扩 展 ...
- 图灵学院JAVA互联网架构师专题学习笔记
图灵学院JAVA互联网架构师专题学习笔记 下载链接:链接: https://pan.baidu.com/s/1xbxDzmnQudnYtMt5Ce1ONQ 密码: fbdj如果失效联系v:itit11 ...
- (转)《深入理解java虚拟机》学习笔记3——垃圾回收算法
Java虚拟机的内存区域中,程序计数器.虚拟机栈和本地方法栈三个区域是线程私有的,随线程生而生,随线程灭而灭:栈中的栈帧随着方法的进入和退出而进行入栈和出栈操作,每个栈帧中分配多少内存基本上是在类结构 ...
随机推荐
- idea创建django项目
1.环境.版本 os:windows10 ide:idea python:2.7 django:1.11.25 其他的python.django不确定这么弄会不会有其他问题. 2.python 官网下 ...
- 内网渗透之信息收集-windows系统篇
windows 用户相关 query user #查看当前在线的用户 whoami #查看当前用户 net user #查看当前系统全部用户 net1 user #查看当前系统全部用户(高权限命令) ...
- 音频相关 ALSA ffmpeg ffplay 命令用法 g7xx
采样率: samples 441100 每秒 DAC/ADC 采样的频率,声卡一般还支持 48k 8k 等模式. 通道:channels 2声道 左右声道 也有单声道的声音,5.1 声道 位数: 16 ...
- redis 出现(error) MISCONF Redis is configured to save RDB snapshots, but is currently not able to persist on disk. Commands that may modify the data set are disabled. Please check Redis logs for details
如果在ubuntu安装的redis含端口使用,但是某些时候常常出现 (error) MISCONF Redis is configured to save RDB snapshots, but is ...
- Python数据科学手册(2) NumPy入门
NumPy(Numerical Python 的简称)提供了高效存储和操作密集数据缓存的接口.在某些方面,NumPy 数组与 Python 内置的列表类型非常相似.但是随着数组在维度上变大,NumPy ...
- Angular介绍
Angulay介绍 1.介绍:是一个用于Html和TypeScript构建客户端应用平台与框架.Angular 本身就是用 TypeScript 写成的.基本构造块是 NgModule,它为组件提供了 ...
- Mysql 查询天、周,月,季度、年的数据
Mysql 查询天.周,月,季度.年的数据 今天 select * from 表名 where to_days(时间字段名) = to_days(now()); 昨天 SELECT * FROM 表名 ...
- Natas26 Writeup(PHP反序列化漏洞)
Natas26: 打开页面是一个输入坐标点进行绘图的页面. <html> <head> <!-- This stuff in the header has nothing ...
- .NET Core技术研究-HttpContext访问的正确姿势
将ASP.NET升级到ASP.NET Core之后,相信大家都会遇到HttpContext.Current无法使用的问题.这也是我们迁移ASP.NET Core必须解决的问题. 本文我们详细讨论一下, ...
- mybatis入门详解
一.mybatis-config.xml文件 <?xml version="1.0" encoding="UTF-8" ?> <!DOCTYP ...