内容简介:前言:要弄清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是一个特殊的垃圾收集器,既可以作为新生代的垃圾收集器,也可以作为老年代的垃圾收集器。
更加详细的垃圾收集器的知识,可以阅读《深入理解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),用于回收那些已经“死亡”的对象。
下图为堆中分代
在方法区中进行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的对象,就是没有和引用链上相连的并且经过第一次标记,没有“自救”成功的对象。
以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网
猜你喜欢:- 【Java转Go】弄清GOPATH
- 十个问题弄清 JVM & GC(二)
- ????彻底弄清 this call apply bind 以及原生实现
- 机器学习和深度学习中值得弄清楚的一些问题
- go 学习笔记之咬文嚼字带你弄清楚 defer 延迟函数
- java – 在过滤器中修改Jersey InputStream.无法弄清楚如何在Jersey资源中访问修改后的inputStream
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
Data Structures and Algorithm Analysis in Java
Mark A. Weiss / Pearson / 2011-11-18 / GBP 129.99
Data Structures and Algorithm Analysis in Java is an “advanced algorithms” book that fits between traditional CS2 and Algorithms Analysis courses. In the old ACM Curriculum Guidelines, this course wa......一起来看看 《Data Structures and Algorithm Analysis in Java》 这本书的介绍吧!