弄清Java虚拟机GC的运行过程

栏目: Java · 发布时间: 5年前

内容简介:前言:要弄清Java虚拟机GC的整个过程,就得弄明白Java虚拟机用什么来进行GC?Java虚拟机在哪里GC?什么时候GC?GC什么?GC(Garbage Collection)垃圾收集,JVM一个非常重要的功能。本文将围绕着JVM的GC这个动作展开,来过一遍GC的整个运作过程。JVM是GC的发起者,准确说是VMThread是GC的发起者,那用什么来进行GC呢?很显然,用到的是垃圾收集器来进行GC的。而垃圾收集器,可以根据堆中的分代,分为不同类型的垃圾收集器。

前言:要弄清 Java 虚拟机GC的整个过程,就得弄明白Java虚拟机用什么来进行GC?Java虚拟机在哪里GC?什么时候GC?GC什么?

开门见山

GC(Garbage Collection)垃圾收集,JVM一个非常重要的功能。本文将围绕着JVM的GC这个动作展开,来过一遍GC的整个运作过程。

JVM用什么来进行GC

JVM是GC的发起者,准确说是VMThread是GC的发起者,那用什么来进行GC呢?很显然,用到的是垃圾收集器来进行GC的。而垃圾收集器,可以根据堆中的分代,分为不同类型的垃圾收集器。

新生代(Young generation)

  • Serial垃圾收集器
  • ParNew垃圾收集器
  • Parallel Scavenge垃圾收集器

老年代(Tenured generation)

  • CMS垃圾收集器
  • Parallel Old垃圾收集器
  • Serial Old垃圾收集器

G1是一个特殊的垃圾收集器,既可以作为新生代的垃圾收集器,也可以作为老年代的垃圾收集器。

弄清Java虚拟机GC的运行过程

更加详细的垃圾收集器的知识,可以阅读《深入理解JVM》这本书。

JVM在哪里进行GC

JVM的GC动作只在两个地方回收————堆和方法区。(JDK8的metaspace的GC,这里暂不讨论。如果还有其他内存区域发生垃圾回收,请指正)

在堆取进行GC

首先,得了解堆是什么,有什么作用? 言简意赅——总结Java内存区域和常量池

这里需要知道,JVM的GC采用了分代思想,所以堆被分成了新生代和老年代,而新生代又被细分为Eden区和From survivor和To survivor区。当类被JVM加载后,Java应用程序运行然后某个对象被new,这个对象就会被分配到堆中的新生代的Eden区(对象优先被分配到Eden区),如果Eden区域没有足够的内存来分配给该对象,就会触发minor GC来清除已经“死亡”的对象,这样才能将新清出的内存分配给该对象,经过GC都还存活的对象,会被移至From survivor区中。由于新生代采用的复制算法,Eden区存活对象和From survivor区的存活对象将被复制到To survivor区中。在To survivor区中的对象,每经过一次GC,对象中的“年龄计数器”就会加1,如果超过了晋升为老年代的年龄阈值时(默认为15)对象就会晋升到老年代中。

由于老年代里存放的都是大对象、存活时间较久的对象,因此老年代一般都是用标记-整理算法或标记-清除算法。当老年代对象没法再分配内存时,会触发一次Major GC(Full GC),用于回收那些已经“死亡”的对象。

下图为堆中分代

弄清Java虚拟机GC的运行过程

在方法区中进行GC

在堆中进行GC一般可以回收70%~95%的空间,相比在方法区中进行GC效率是非常低的。但是效率低不代表不进行GC。永久代的垃圾收集主要回收两部分内容:废弃常量和无用的类。

JVM什么时候进行GC

在上文中,已经讲到了JVM什么时候进行GC。就是在Eden区没有足够内存分配给对象的时候进行Minor GC,在老年代没法再分配内存给大对象以及“老”对象的时候进行的Major GC(full GC)。这里谈一谈Minor GC和Major GC:

  • 新生代GC(Minor GC):指发生在新生代的垃圾收集动作,因为Java对象大多都具备招生夕灭的特性,所以Minor GC非常频繁,一般回收速度也非常快。
  • 老年代GC(Major GC/Full GC):指发生在老年代的GC,出现了Major GC,经常会伴随至少一次的Minor GC(并不是绝对的,例如Parallel Scavenge垃圾收集器就直接进行Major GC的策略选择过程)。Major GC的速度一般比Minor GC慢10倍以上。

JVM对什么对象进行GC

这里,首先得了解对象在什么情况下会被进行GC?

是“真正死亡”的对象吗?

那么,对象怎么才能被判定为“真正死亡”呢?JVM是通过可达性分析来进行分析的。可达性分析就是通过从GC Roots为起点,判断是否有一个引用链与被判断的对象相连,如果相连这代表这个对象还“活着”,是可用的。然而,一个对象被真正判定为“死亡”,需要进行两次标记(被标记为可回收对象),然后在下一次JVM进行GC的时候,才被真正的回收掉。如果一个对象没有与GC Roots的引用链相连接,也并没有被真正判定为“死亡”,而是进行第一次标记,然后在第二次标记之前会进行“自救”过程。所谓的“自救”就是在第二次被标记之前,需要重新与引用链相连接。在第一次被标记后,对象会进行筛选,筛选的条件为是否有必要进行执行finalize()方法。如果没有必要执行finalize()方法,则就等待第二次被标记;如果有必要执行finalize()方法,则会先将对象放置在一个叫F-Queue的队列中,然后等待虚拟机通过Finalizer线程去触发对象的finalize()方法,然后在finalize()方法里面,对象就开始自救的过程。对象自救可以通过把this赋值给某个类变量或者对象的成员变量,就实现了和引用链重新连接的目的——自救成功。因此在第二次标记的时候就会把对象从F-Queue队列中移除,然后虚拟机会在F-Queue中进行第二次小规模的标记,然后就等待下一次GC的来临。

结论:

所以,从上面分析的结果来看,JVM进行GC的对象,就是没有和引用链上相连的并且经过第一次标记,没有“自救”成功的对象。


以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

U一点·料

U一点·料

阿里巴巴集团 1688用户体验设计部 / 机械工业出版社 / 2015-7-13 / 79.00元

《U一点·料——阿里巴巴1688UED体验设计践行之路》是1688UED团队历经多年实践之后的心血之作,书中以“道─术─器”的思路为编排脉络,从设计观、思考体系、方法论上层层剖析,将零散的行业knowhow串成体系,对“UED如何发展突破”提出了自己的真知灼见。该书重实战、讲方法、求专业、论文化,是一部走心的诚意之作。 本书作者从美工到用户体验设计师,从感性随意到理性思考,从简单的PS做图到......一起来看看 《U一点·料》 这本书的介绍吧!

JS 压缩/解压工具
JS 压缩/解压工具

在线压缩/解压 JS 代码

HSV CMYK 转换工具
HSV CMYK 转换工具

HSV CMYK互换工具