快来,看完它再也不怕面试被问GC了(*^▽^*)

一、jvm内存模型

我的另一篇博客关于内存模型进行过详细介绍,欢迎查看
JVM内存模型详解
堆得分区这里需要了解一下,下面垃圾算法会用到。就是把堆分为伊甸区和Survivor区,Survivor区又分了一个From和To。伊甸:Survivor约等于8:1。Java8中已经移除了永久代,新加了一个叫做元数据区的native内存区。
在这里插入图片描述

二、GC概念和垃圾判定

1、 什么是GC?

GC(Garbage Collection)就是垃圾回收,其实就在用来帮你擦屁股的,好让你安心写代码,不用管内存释放,对象清理的事情了。在Java虚拟机中,存在自动内存管理和垃圾清扫机制,是不是觉得很爽。

2、为什么要有GC?

电脑的内存大小的不变的,当我们使用对象的时候,如使用New关键字的时候,就会在内存中生产一个对象,但是我们在使用JAVA开发的时候,当一个对象使用完毕之后我们并没有手动的释放那个对象所占用的内存,就这样在使用程序的过程中,对象越来越多,当内存存放不了这么多对象的时候,电脑就会崩溃了,JAVA为了解决这个问题就推出了这个自动清除无用对象的功能。

3、怎么判定垃圾

既然要回收垃圾,就要知道什么是垃圾。
引用计数法
顾名思义,整一个count来给对象计数,有引用指向时就+1,引用离开时就-1,count=0时,说明对象死了。这么简单,为什么JVM却不用它来管理内存呢?很好理解,要是三个人之间形成了三角恋,你觉着谁能脱单?引用计数法就没法解决这种具有相互循环引用的对象。
可达性分析法
那java采用什么方法呢,就是可达性分析法。简单来说就是找一个根节点,往下遍历,它能到的地方就是活对象,到不了的jvm就会对其进行回收。这个根节点称为GC roots;
在这里插入图片描述
在Java语言中,可作为GC Roots的对象包含下面几种:
1、虚拟机栈(栈帧中的本地变量表)中引用的对象
2、方法区中类静态属性引用的对象
3、方法区中常量引用的对象
4、本地方法栈中JNI(Native方法)引用的对象

4、四种引用介绍

在JDK1.2之后,Java对引用的概念做了扩充,将引用分为强引用、软引用、弱引用、虚引用四种,强度依次递减。

强引用: 强引用指的是在程序代码之中普遍存在的,类似于"Object obj = new Object()"这类的引用,只要强引用还存在,垃圾回收器永远不会回收掉被引用的对象实例。

软引用 : 软引用是用来描述一些还有用但是不是必须的对象。对于软引用关联着的对象,在系统将要发生内存溢出之前,会把这些对象列入回收范围之中进行第二次回收。如果这次回收还是没有足够的内存,才会抛出内存溢出异常。在JDK1.2之后,提供了SoftReference类来实现软引用。

弱引用 : 弱引用也是用来描述非必需对象的。但是它的强度要弱于软引用。被弱引用关联的对象只能生存到下一次垃圾回收发生之前。当垃圾回收器开始进行工作时,无论当前内容是否够用,都会回收掉只被弱引用关联的对象。在JDK1.2之后提供了WeakReference类来实现弱引用。

虚引用 : 虚引用也被称为幽灵引用或者幻影引用,它是最弱的一种引用关系。一个对象是否有虚引用的存在,完全不会对其生存时间构成影响,也无法通过虚引用来取得一个对象实例。为一个对象设置虚引用的唯一目的就是能在这个对象被收集器回收时收到一个系统通知。在JDK1.2之后,提供了PhantomReference类来实现虚引用。

5、回收方法区

方法区(永久代)的垃圾回收主要收集两部分内容 :
废弃常量和无用的类
回收废弃常量和回收Java堆中的对象十分类似。以常量池中字面量(直接量)的回收为例,假如一个字符串"abc"已经
进入了常量池中,但是当前系统没有任何一个String对象引用常量池的"abc"常量,也没有在其他地方引用这个字面
量,如果此时发生GC并且有必要的话,这个"abc"常量会被系统清理出常量池。常量池中的其他类(接口)、方法、
字段的符号引用也与此类似。
判断一个类是无用类
1、该类所有实例都已经被回收(即在Java堆中不存在任何该类的实例)
2.、加载该类的ClassLoader已经被回收
3.、该类对应的Class对象没有在任何其他地方被引用,无法在任何地方通过反射访问该类的方法

三、 垃圾回收算法

1、 标记-清除算法

分为"标记"和"清除"两个阶段 : 首先标记出所有需要回收的对象,然后统一回收。有两点不足
1、 效率问题 : 标记和清除这两个过程的效率都不高
2.、空间问题 : 标记清除后会产生大量不连续的内存碎片,空间碎片太多可能会导致以后在程序运行中需要分配较大对象时,无法找到足够连续内存而不得不提前触发另一次垃圾收集。

在这里插入图片描述

2 、复制算法(新生代回收算法)

将可用内存按容量划分为大小相等的两块,每次只使用其中的一块。当这一块的内存用完了,就将还存活着的对象复制到另外一块上面,然后再把已使用过的内存空间一次清理掉。这样做的好处是每次都是对整个半区进行内存回收,内存分配时也就不需要考虑内存碎片等复杂情况,只需要移动堆顶指针,按顺序分配即可
在这里插入图片描述

3 、标记-整理算法(老年代回收算法)

复制收集算法在对象存活率较高时会进行比较多的复制操作,效率会变低。因此在老年代一般不能使用复制算法。
针对老年代的特点,提出了一种称之为"标记-整理算法"。标记过程仍与"标记-清除"过程一致,但后续步骤不是直接对可回收对象进行清理,而是让所有存活对象都向一端移动,然后直接清理掉端边界以外的内存。流程图如下:
在这里插入图片描述

4、 分代收集算法

当前JVM垃圾收集都采用的是"分代收集(Generational Collection)"算法,这个算法并没有新思想,只是根据对象存
活周期的不同将内存划分为几块。一般是把Java堆分为新生代和老年代。在新生代中,每次垃圾回收都有大批对象死去,只有少量存活,因此我们采用复制算法;而老年代中对象存活率高、没有额外空间对它进行分配担保,就必须采用"标记-整理"算法。

四、 七种垃圾收集器

1、Serial收集器(新生代,串行):最古老,最稳定,它工作时其他线程必须暂停。
2、ParNew收集器(新生代,并行):是Serial收集器的多线程版本。
3、Parallel Scavenge(新生代,并行)Parallel收集器更关注系统的吞吐量,使用复制算法。
4、Serial Old收集器(老年代,串行):使用标记整理,是Serial的老年版
5、Parallel Old 收集器(老年代,并行),Parallel Old是Parallel Scavenge收集器的老年代版本,使用多线程和“标记-整理”算法
6、CMS收集器(老年代,并行),是一种以获取最短回收停顿时间为目标的收集器。
7、G1收集器,G1 (Garbage-First)是一款面向服务器的垃圾收集器,主要针对配备多颗处理器及大容量内存的机器. 以极高概率满足GC停顿时间要求的同时,还具备高吞吐量性能特征

五、 java 内存分配与回收以及 Minor GC 和Major GC

答:对象优先在堆的 Eden 区分配,大对象直接进入老年代。长期存活的对象将直接进入老年代.,当 Eden 区没有足够的空间进行分配时,虚拟机会执行一次 Minor GC。Minor Gc 通常发生在新生代的 Eden 区,在这个区的对象生存期短,往往发生 Gc 的频率较高,回收速度比较快;Full Gc/Major GC 发生在老年代,一般情况下,触发老年代 GC的时候不会触发 Minor GC,但是通过配置,可以在 Full GC 之前进行一次 MinorGC 这样可以加快老年代的回收速度。
面试题: 请问了解Minor GC和Full GC么,这两种GC有什么不一样吗
1、Minor GC又称为新生代GC : 指的是发生在新生代的垃圾收集。因为Java对象大多都具备朝生夕灭的特性,因此Minor GC(采用复制算法)非常频繁,一般回收速度也比较快。
2、Full GC 又称为 老年代GC或者Major GC : 指发生在老年代的垃圾收集。出现了Major GC,经常会伴随至少一次的Minor GC(并非绝对,在Parallel Scavenge收集器中就有直接进行Full GC的策略选择过程)。
3、Major GC的速度一般会比Minor GC慢10倍以上。

猜你喜欢

转载自blog.csdn.net/chris__x/article/details/106789234