看了这篇虚拟机 GC,可以跟面试官扯半天

GC的基础知识

1.什么是GC

GC 的全称是Garbage Collection,垃圾回收。
垃圾回收的目的是什么?
1:开发人员只管使用内存,无需关注内存的清除工作,使编程变得更简单。
2:JAVA开发的系统更加健壮,避免因为垃圾忘记回收导致内存溢出。

2 什么是垃圾

  1. 方法执行完后,方法内定义的变量以及对象。
  2. for , each while 执行完当前轮循后, 循环里定义的变量以及对象。
  3. if 执行完后,if内部定义的变量以及对象。
    PS:实例的变量对象有两种,一种存在堆里,一种存在栈里。 这里说的对象必须是存在堆里的。存在栈的对象无需回收。

2.如何定位垃圾

  1. 引用计数(ReferenceCount)
    在 Java 中,引用和对象是有关联的。如果要操作对象则必须用引用进行。因此,很显然一个简单的办法是通过引用计数来判断一个对象是否可以回收。简单说,即一个对象如果没有任何与之关联的引用,即他们的引用计数都不为 0,则说明对象不太可能再被用到,那么这个对象就是可回收 对象。

  2. 根可达算法(RootSearching)
    为了解决引用计数法的循环引用问题,Java 使用了可达性分析的方法。通过一系列的“GC roots” 对象作为起点搜索。如果在“GCroots”和一个对象之间没有可达路径,则称该对象是不可达的。要注意的是,不可达对象不等价于可回收对象,不可达对象变为可回收对象至少要经过两次标记过程。两次标记后仍然是可回收对象,则将面临回收
    GCroots包括:

    1. 虚拟机栈(栈帧中的局部变量区,也叫做局部变量表)中引用的对象
    2. 方法区中的类静态属性引用的对象
    3. 方法区中常量引用的对象
    4. 本地方法栈中JNI(Native方法)引用的对象

3.常见的垃圾回收算法

1): 标记清除(mark sweep)

首先,要对需要回收的对象进行标记,然后要对这些被标记的对象进行收集。如下图所示
在这里插入图片描述

优点
1、算法简单
缺点
​ 1、碎片严重。清除需要被清理的对象后剩下的内存都是破碎的,如果要创建大对象,可能会因为找不到足够的内存而再次触发垃圾收集。
​ 2、效率低。标记和清除的效率相对于其他算法来说都不高,标记的原理就是从GC Roots往下遍历,能被遍历到的对象就是存活对象,剩下不能被遍历到的对象就是需要被标记清除的。而清除时,是根据是否被标记,然后一个一个清除未被标记的。。这个效率就比较低了(遍历了两次才执行清除)。

2:拷贝算法 (copying) - 没有碎片,浪费空间

大致原理,把内存分为两块,分别命名为A、B,A用于创建对象,B则是空闲内存(暂时不存放任何对象),当要进行垃圾回收时,把A中能被GC roots关联到的对象(存活对象)全部复制到B中,然后把A中的所有内存空闲都清理掉。 如下图所示。轮循重复以上步骤清除BABABA。
复制算法适用于年轻代。有统计得出,年轻代的内存95%都是朝生夕灭的,只有5%的内存是存活的。
在这里插入图片描述

优点
1、没有碎片。内存总有一部分是完整的一块,不会出现破碎内存的情况。
​ 2、高效。一般情况下,存活对象只占所有对象中的很少一部分,百分之九十以上的对象都是要被清理掉的,所以复制存活对象到另一块内存中所操作的对象数量就比较少,这样的话,自然而然效率就高了。像标记-清除算法,是先要标记出所有不能存活的对象才行,意味着要对大多数对象进行操作。
缺点
1、浪费内存。需要提供两块内存,一用一备 。

3:标记压缩(mark compact)

标记-压缩算法,那么它也分为两个阶段。先标记(mark),再压缩(compact)。如下图所示。 其中标记阶段跟标记-清除算法中的标记阶段是一样的。而对于压缩阶段,它的工作就是移动所有的可达对象到堆内存的同一个区域中,使他们紧凑的排列在一起,从而将所有非可达对象释放出来的空闲内存都集中在一起,通过这样的方式来达到减少内存碎片的目的。
在这里插入图片描述

优点
​ 没有碎片
缺点
效率偏低(两遍扫描,标记与压缩)

4:分代清理

1.8之前java虚拟机都是使用分代回收,如下图所示。
在这里插入图片描述

1、年轻代EDEN,使用拷算法。年轻代的回收也叫Young GC,YGC频繁执行清除。
a) 据统计得出,新创建的对象95%都是朝生夕灭的。第一轮的GC,只有5%的对象能存活下来。所以
新生代内存按照8:1:1的比例分为一个Eden区和两个survivor(survivor0,survivor1)区。
b) 第一轮GC,把Eden区存活对象复制到survivor0区
c) 第二轮GC,把Eden区存活对象+survivor0存活对象复制到survivor1区。
d) 第三轮GC,把Eden区存活对象+survivor1存活对象复制到survivor0区。
e) 轮循重复c,d。
2、老年代发生的GC也叫做Full GC,Full GC相对低频率执行,Full GC主要使用 标记清除法。
a) 在年轻代中经历了N次垃圾回收后仍然存活的对象,就会被放到年老代中。因此,可以认为年老代中存放的都是一些生命周期较长的对象。
b) 内存比新生代也大很多(大概比例是1:2),当老年代内存满时触发Full GC,Full GC发生频率比较低,老年代对象存活时间比较长,存活率标记高。

回收器

目前比较流行的垃圾收集器有七种。如下图所示。
在这里插入图片描述
根据分区回收可以分为:

1:年轻代:Serial, ParNew,Parallel Scavenge 。
2:老年代:CMS,Serial Old, Parallet Old用于老年代回收。
3:不分代:G1。

Serial: 单线程,使用拷贝算法。GC过程STW。
PartNew:多线程,使用拷贝算法,GC过程STW。实际上就是Serial的多线程版本。
Parallel Scavenge:多线程,使用拷贝算法,GC过过程STW。跟ParNew几乎一样,那它有什么特别之处?

1:实际上ParNew配合老年代回收器是CMS,Serialold,而Parallel Scavenge配合的是Serial Old、Parallel Old。
2:ParNew关注的是尽可能的缩短GC的时间(STW时间),而Parallel Scavenge 更关注吞吐量。
PS :即 吞吐量= 运行 用户 代码 时间/( 运行 用户 代码 时间+ 垃圾 收集 时间), 虚拟 机 总共 运行 了 100 分钟, 其中 垃圾 收集 花掉 1 分钟, 那 吞吐量 就是 99%。

Serial Old: Serial 老年代版本。
Parallel Old: Parallel Scavenge老年代版本。
CMS: 是垃圾回收器的一个重要里程碑。目标是最大程度减少GC时STW时间。比其它回收器都复杂一些。它包括以下流程:初始标记,并发标记,重新标记,并发清除。如下图所示。其中:

初始标记:STW,只找出根关联的对象。STW时间很短。
并发标记:非STW,标记出垃圾。时间长,并发进行。。
重新标记:STW,再次确认已标的垃圾。
并发清除:非STW,清除垃圾。
在这里插入图片描述

G1:CMS的升级方案。具有以下特点:

并行与并发:充份利用多CPU的优势,缩短STW时间。
分代收集:G1不需要与其它回收器配合,G1能分别处理年轻代与老年代。
可预测的停顿:能让使用者明确指定在一个长度为M毫秒的时间片段内,消耗在垃圾收集上的时间 不得超过N毫秒。
G1回收的流程与CMS差不多。如下图所示
在这里插入图片描述

本人能力有限,如有错误请指出。
参考文献:
周志明. 深入理解Java虚拟机:JVM高级特性与最佳实践(第2版)
马老师视屏。
https://www.cnblogs.com/sunniest/p/4575144.html
https://www.jianshu.com/p/698eb5e1ccb9

发布了27 篇原创文章 · 获赞 64 · 访问量 1万+

猜你喜欢

转载自blog.csdn.net/richyliu44/article/details/105281456
今日推荐