请简述 JVM 垃圾回收原理。

JVM的垃圾回收目的是为了将JVM堆中已经不再被使用的对象清理掉以释放内存。

通过可达性算法进行标识

通过标记来识别哪些对象需要被回收,标记的方法如下:

  • 从线程栈帧中的局部变量或方法区中的静态变量开始出发,将引用了这些变量的对象进行标记
  • 再看这些被标记的对象有没有被引用,如果有继续标记
  • 这样最终没有被标记的对象,就是需要被回收的对象

回收的方法有三种,清理,压缩和复制。

  • 清理:将垃圾对象占用的内存空间标记为空闲,并记录在一个空闲列表中,有内存申请需要时,才会把这些空间分配出去。
  • 压缩:从堆内存的头部开始,将存活的对象拷贝到一段连续的内存中,那么剩下的空间就是可用的了,并且是连续的。
  • 复制:将堆空间分为两部分,只在其中一部分中创建的对象,当这部分空间用完时,将标记的对象复制到另一个空间中,这样这个空间的内存就是可用的了。

分代回收

将堆内存分为新生代和老年代,新生代又分为Eden区,From区,To区。

  • 在Eden区中申请空间创建对象
  • Eden满了以后,遍历Eden区判断哪些对象可回收,启动young GC
  • 将标记的对象拷贝到from区,Eden区变空
  • 一段时间后Eden区满,将Eden区和From区的标记对象拷贝到To区,From区和Eden区变空
  • 再一段时间后Eden区满,将Eden去和To区的标记对象拷贝到From区,To区和Eden去变空
  • 多次拷贝后仍被标记的对象,就会被拷贝到老年代

垃圾回收器的算法

  • 串行回收器:单独启动一个线程专门用于垃圾回收,当GC时所有线程都停止工作『stop the world』,等待这个线程的GC完成
  • 并行回收器:并行是指可以启动多个线程进行垃圾回收;当GC发生时,仍然会『stop the world』,但可以根据cpu核心数,启动多个线程进行GC,效率更高。
  • 并发垃圾标记清理(CMS):并发是指GC线程和业务线程可以同时工作,同时也就意味着可能会出现重标记,重标记期间还是会发生『stop the world』,比并行回收器,对业务线程影响较小,但更好资源。
  • G1回收器:jdk1.7高版本开始引入G1,是目前比较高效的算法