阅读 149

【Android面试-Java-V05】Java GC 垃圾回收

考察点

  1. 垃圾回收机制,分代回收,各个代用什么算法
  2. 四大引用

JVM如何判断一个对象实例是否应该被回收?

首先判断对象是否存活,

1. 对象存活的判断方法

  • 引用计数器算法

引用计数器的算法原理:给对象添加一个引用计数器,每当有一个地方引用它时,计数器的值就会加1;当引用失效时,计数器就会减1;在任何时刻计数器的值为0的对象就是不可能再被使用的,也就是被回收的对象。

优点:效率高 缺陷:无法解决对象之间循环引用的问题,对于循环引用的对象,无法进行回收(主流JVM并未采用这种算法)

  • 可达性分析算法(GC Roots)

在主流的JVM实现中,都是通过可达性分析算法来判断对象时候存活的。其基本思想:通过一系列被称为"GC Roots"的对象作为起始点,从这些节点开始向下搜索,搜索走过的路径称为引用链,当一个对象到GC Roots对象没有任何引用链相连,就认为GC Roots到这个对象是不可达的,判定为不可用对象,可以被回收。

Java虚拟机将以下对象定义为 ==GC Roots== :

  • Java虚拟机栈中引用的对象,虚拟机栈中(栈帧)
  • 静态属性引用的对象,static对象
  • 常量引用的对象,final对象
  • 本地方法栈中引用的对象,nio

image

2.垃圾收集算法

  • 标记清除算法

从根集合进行扫描,对存活的对象进行标记,完毕后清除未标记对象

  • 复制算法

将内存一分为二,每次使用一块,将存活的对象复制到另外一块。

时间上效率低,空间上产生内存碎片。

  • 标记压缩算法

类似于标记清除,移动存活的对象向内存一端,然后清理边界以外的内存。

  • 分代收集算法

不同的对象的生命周期(存活情况)是不一样的,而不同生命周期的对象位于堆中不同的区域,因此对堆内存不同区域采用不同的策略进行回收可以提高 JVM 的执行效率。

当代商用虚拟机使用的都是分代收集算法:

新生代对象存活率低,就采用 复制算法 ;老年代存活率高,就用标记清除算法或者标记整理算法。

Java堆内存一般可以分为新生代、老年代和永久代三个模块。

新生代、老年代和永久代

  • 新生代:一般新创建的对象放在新生代,新生代内存按8:1:1分为eden和两个survior区。大部分对象放在eden区,垃圾回收时将eden区存活的对象复制到survior0中,然后清除eden。当survior0满了,则复制所有存活对象到survior1。然后清楚eden和survior0,再交换survior0和survior1。
  • 老年代:存放生命周期较长的对象,大对象直接进入老年代(连续内存空间)在新生代中经历了N次垃圾回收后仍然存活的对象就会被放到老年代中。老年代如果满了回发生FullGC
  • 永久代:用于存放静态文件,java类,方法。

image

垃圾回收有两种类型,Minor GC 和 Full GC。

  • Minor GC:对新生代进行回收,不会影响到年老代。因为新生代的 Java 对象大多死亡频繁,所以 Minor GC 非常频繁,一般在这里使用速度快、效率高的算法,使垃圾回收能尽快完成。

  • Full GC:也叫 Major GC,对==整个堆==进行回收,包括新生代和老年代。由于Full GC需要对整个堆进行回收,所以比Minor GC要慢,因此应该尽可能减少Full GC的次数,导致Full GC的原因包括:老年代被写满、永久代(Perm)被写满和System.gc()被显式调用等。

图解Java 垃圾回收机制


Java四大引用类型

  • 强引用(StrongReference)

当内存空间不足,Java虚拟机宁愿抛出OutOfMemoryError错误,使程序异常终止,也不会靠随意回收具有强引用的对象来解决内存不足的问题。 ps:强引用其实也就是我们平时A a = new A()这个意思。

  • 软引用(SoftReference)

如果一个对象只具有软引用,则内存空间足够,垃圾回收器就不会回收它;如果内存空间不足了,就会回收这些对象的内存

  • 弱引用(WeakReference)

只具有弱引用的对象拥有更短暂的生命周期。在垃圾回收器线程扫描它所管辖的内存区域的过程中,一旦发现了只具有弱引用的对象,不管当前内存空间足够与否,都会回收它的内存。

  • 虚引用(PhantomReference)(基本没有用)

虚引用并不会决定对象的生命周期。如果一个对象仅持有虚引用,那么它就和没有任何引用一样,在任何时候都可能被垃圾回收器回收。

关注下面的标签,发现更多相似文章
评论