1、简述Java垃圾回收机制

Java中不允许程序员自己操作内存管理,也不需要显示的去释放一个对象的内存,JVM虚拟机会自动执行管理这些内存。JVM虚拟机中有一个垃圾回收线程,它是低优先级的,在无特殊情况时不会触发执行,当虚拟机空闲或者当前堆内存不足时才会执行触发,它将自动扫描那些当前没有被引用的对象将它们添加到回收集合中,进行回收。

2、GC是什么?为什么要GC

GC是垃圾回收集合的意思(Gabage Collection),在编程中例如C语言它是通过程序员处理内存的,然而内存处理往往容易出现各种问题忘记处理或者处理不当、操作错误内存等,这种回收会导致程序或系统的不稳定甚至导致崩溃,JAVA为了避免这种情况的发生优化了这一环节,提供GC功能自动监测对象是否超过作用域进而实现自动回收内存,并且JAVA不提供释放已分配内存的显示操作的方法,仅运行程序员提醒JVM此方法/变量可以被回收的方法(System.gc(),此函数建议JVM进行主GC,虽然只是建议而非一定,但很多情况下它会触发主GC,从而增加主GC的频率,也即增加了间歇性停顿的次数。)

3、垃圾回收的优点和原理。并考虑2种回收机制

1、Java最显著的优点除了跨平台外还有一点就是垃圾回收机制,GC的存在使程序员不用去考虑内存管理的问题。2、这个垃圾回收机制让Java中的对象不再有“作用域”的概念,只需要考虑引用对象的“作用域”。3、其还有效的防止了内存泄漏的问题,让程序能够有效的使用可用的内存。4、垃圾回收器通常作为一个单独的低级别的线程运行,在不可预知的情况下对虚拟机内存堆中已经死亡或者长时间没有被使用的对象进行清除和回收内存。5、程序员不能实时显示的对某一个对象或者所有对象调用垃圾回收器进行垃圾回收。6、垃圾回收中将“垃圾”分级处理,分别是分代复制垃圾回收、标记垃圾回收、增量垃圾回收。

4、垃圾回收器的基本原理是什么?垃圾回收器可以马上回收内存吗?有什么办法主动通知虚拟机进行垃圾回收?

通常来说当对象被创建时,GC就开始监控这个对象的地址、大小以及其使用情况。并且GC采用有向图(一种图表算法)的方式记录和管理堆(heap)中的所有对象。通过这种方式确定那些对象是"可达的",那些对象是"不可达的"。当GC确定一些对象为"不可达"时,GC就有责任回收这些内存空间。
垃圾回收器是可以马上回收内存的(这种需要看特殊情况)
编程人员可以手动的执行System.gc(),通知GC运行并回收垃圾,但是JAVA中并不提倡这样做也不保证GC就一定会执行。

5、Java 中都有哪些引用类型?

强引用:发送GC的时候不会被回收
软引用:有用但不是必须的对象,在发送内存溢出之前会被回收
弱引用:有用但不是必须的对象,在下一次GC时会被回收
虚引用:无法通过虚引用获得对象,用PhantomReference实现虚引用,虚引用的用途是在GC时返回一个通知

6、怎么判断对象是否可以被回收?

垃圾收集器在做垃圾回收的时候,首先需要判定哪些对象是「存活」的,是不可以被回收的;哪些对象已经「死掉」了,需要被回收。两种方法来判断:
引用计数器法:为每个对象创建一个引用计数,有对象引用时计数器 +1,引用被释放时计数 -1,当计数器为 0 时就可以被回收。它有一个缺点不能解决循环引用的问题。
可达性分析算法:从 GC Roots 开始向下搜索,搜索所走过的路径称为引用链。当一个对象到 GC Roots 没有任何引用链相连时,则证明此对象是可以被回收的。

7、在Java中,对象什么时候可以被垃圾回收

当对象对当前使用的这个对象的应用程序变得不可触及的时候,这个对象就可以被回收了。

8、JVM中的永久代中会发生垃圾回收吗?
垃圾回收不会发生在永久代,如果永久代满了或者超过临界值时,会触发完全垃圾回收(Full GC)。如果你仔细查看垃圾收集器的输出信息,就会发现永久代也是会被回收的。这就是为什么正确的永久大小对避免Full GC 是非常重要的原因。(Java8之前的JVM内存区包含新生代、老年代、永久代,但是在Java8之后设计人员将永久代去除并新增加了一个元数据区的native内存区)

9、说一下 JVM 有哪些垃圾回收算法?

标记-清除算法:标记无用的对象,然后进行清除回收。缺点效率不高,无法清除垃圾碎片。
复制算法:按照容量划分两个大小相等的内存区域,当一块用完的时候将活着的对象复制到另一块区域上,然后再把已经使用的内存空间一次清空。缺点:内存使用率不高,只使用了原来的一半。
标记-整理算法:标记无用的对象,让所有存活的对象都向一端移动,然后直接清除掉端边界以外的内存。
分代算法:根据对象的存活周期的不同将内存划分为几块,分别是新生代和老年代,新生代基本采用复制算法,老年代采用标记整理算法。

10、说一下 JVM 有哪些垃圾回收器?

如果说垃圾手机算法是内存回收的方法论,那么垃圾收集器就是内存回收的具体实现。
垃圾回收器按分代划分,用于回收新生代的收集器包括 Serial、PraNew、ParallelScavenge
用于回收老年代的收集器包括 Serial Old、Parallel Old、CMS
用于回收整个Java堆(heap)的 G1 收集器
以上的不同收集器之间实际工作中可以搭配使用
JVM_第1张图片
Serial收集器(采用复制算法):新生代单线程收集器,标记和清理都是单线程,优点是简单高效
ParNew收集器(采用复制算法):新生代收集并行线程的收集器,实际上是Serial收集器的多线程版本,在多核CPU环境下有着比Serial 更好的表现
Parallel Scavenge收集器(复制算法):新生代并行收集器,追求高吞吐量,高效利用CPU。吞吐量 = 用户线程时间 / (用户线程时间+GC线程时间),搞吞吐量可以高效的利用CPU时间,尽快完成程序的运算任务,适合后台应用等对交互相应要求不高的场景
Serial Old收集器 (标记-整理算法):老年代单线程收集器,Serial收集器的老年代版本
Parallel Old收集器 (标记-整理算法):老年代并行收集器,吞吐量优先,Parallel Scavenge收集器的老年代版本
CMS(Concurrent Mark Sweep)收集器(标记-清除算法):老年代并行收集器,以获取最短回收停顿时间为目标的收集器,具有高并发、低停顿的特点,追求最短GC回收停顿时间

G1(Garbage First)收集器 (标记-整理算法):Java堆并行收集器,G1收集器是JDK1.7提供的一个新收集器,G1收集器基于“标记-整理”算法实现,也就是说不会产生内存碎片。此外,G1收集器不同于之前的收集器的一个重要特点是:G1回收的范围是整个Java堆(包括新生代,老年代),而前六种收集器回收的范围仅限于新生代或老年代。

11、详细介绍一下 CMS 垃圾回收器?

CMS 是英文 Concurrent Mark-Sweep 的简称,是以牺牲吞吐量为代价来获得最短回收停顿时间的垃圾回收器。对应的用于服务器响应速度要求较高的应用上。这种垃圾回收器非常适合。在启动 JVM 的参数加上“-XX:+UseConcMarkSweepGC”来指定使用 CMS 垃圾回收器。
值得注意的是,CMS 使用的是标记-清除的算法实现的,所以在 gc 的时候回产生大量的内存碎片,当剩余内存不能满足程序运行要求时,系统将会出现 Concurrent Mode Failure,临时 CMS 会采用 Serial Old 回收器进行垃圾清除,此时的性能将会被降低。

12、新生代垃圾回收器和老年代垃圾回收器都有哪些?有什么区别?

新生代回收器:Serial、ParNew、Parallel Scavenge

老年代回收器:Serial Old、Parallel Old、CMS

整堆回收器:G1

新生代垃圾回收器一般采用的是复制算法,复制算法的优点是效率高,缺点是内存利用率低;老年代回收器一般采用的是标记-整理的算法进行垃圾回收。

13、简述分代垃圾回收器是怎么工作的?

分代回收器有两个分区:老生代和新生代,新生代默认的空间占比总空间的 1/3,老生代的默认占比是 2/3。

新生代使用的是复制算法,新生代里有 3 个分区:Eden、To Survivor、From Survivor,它们的默认占比是 8:1:1,它的执行流程如下:

把 Eden + From Survivor 存活的对象放入 To Survivor 区;

清空 Eden 和 From Survivor 分区;

From Survivor 和 To Survivor 分区交换,From Survivor 变 To Survivor,To Survivor 变 From Survivor。

每次在 From Survivor 到 To Survivor 移动时都存活的对象,年龄就 +1,当年龄到达 15(默认配置是 15)时,升级为老生代。大对象也会直接进入老生代。

老生代当空间占用到达某个值之后就会触发全局垃圾收回,一般使用标记整理的执行算法。以上这些循环往复就构成了整个分代垃圾回收的整体执行流程。