【面试真题拆解13】讲讲JVM的垃圾回收机制?

四季读书网 1 0
【面试真题拆解13】讲讲JVM的垃圾回收机制?

为什么需要垃圾回收?

首先得说清楚,JVM的垃圾回收(GC)到底是干嘛的。

其实就像咱们租房子住,时间长了会产生垃圾,要是不打扫,房子就没法住了。

在Java里,我们写代码会创建很多对象(比如new Person()new ArrayList()),这些对象都存在堆内存里。

但是,堆内存是有限的,要是对象用完了不清理,内存就会被占满,最后报OutOfMemoryError(OOM),程序就挂了。

所以GC的作用就是:自动找到堆里那些“没人用的垃圾对象”,把它们清理掉,腾出内存空间

堆内存划分

JVM把堆分成了新生代和老年代两大块:

  1. 新生代:刚创建的对象优先放在这里。就像“幼儿园”,大部分对象“朝生夕死”(比如方法里的临时变量,方法执行完就没用了)。
  2. 老年代:在新生代里“熬过好几次GC”的对象,会被放到这里。就像“养老院”,这里的对象大多活得比较久(比如Spring容器里的单例Bean)。

那为什么要这么划分呢?

主要还是因为不同生命周期的对象,用不同的回收算法,效率会更高一点。

各代用什么垃圾回收算法?

我当时面试的时候突然懵了,说的不知道, 裂开。。。

对新生代来说,它的特点是:垃圾多,存活对象少(比如100个对象里,可能只有2个活着)。

采用的是复制算法。

JVM把新生代分成三块:

1个Eden区(占80%)和2个Survivor区(From和To,各占10%)。

平时只用Eden区和其中一个Survivor区(比如From)。

新对象先在Eden区分配,当Eden区满了,触发Minor GC(新生代GC),把Eden和From区里活着的对象,复制到To区,然后直接清空Eden和From区,From和To交换角色(下次用Eden和新的From区)。

对老年代来说,它的特点是:存活对象多,垃圾少,而且没有额外的大空间做复制担保,所以不用复制算法,采用的是**标记-清除 **或 标记-整理算法。

标记-清除算法(Mark-Sweep)

这种算法的实现逻辑是,从“GC Roots”(比如主线程、静态变量这些“根”)出发,找到所有活着的对象,做上标记,然后遍历堆内存,把没标记的对象(垃圾)清理掉。

优点是实现简单,但是会产生内存碎片(比如清理后剩下很多小空间,大对象可能放不下)。

标记-整理算法(Mark-Compact)

为了解决内存碎片问题,在“标记-清除”基础上加了个“整理”步骤。

实现逻辑和标记清除算法一样,先标记存活对象,把所有存活对象往内存的一端移动,按顺序排好,最后,直接清空边界以外的内存。

这种算法的优点没有内存碎片,但缺点是需要移动对象,效率比“标记-清除”低。

常见的垃圾回收器

  • Serial:单线程回收,适合客户端应用(比如桌面软件);
  • ParNew:Serial的多线程版,常和CMS配合用;
  • CMS(Concurrent Mark Sweep):主打低延迟(垃圾回收时尽量不让程序停顿太久),适合互联网应用(比如电商后台),用的是“标记-清除”算法;
  • G1(Garbage-First):把堆分成很多小区域,优先回收垃圾多的区域,平衡了吞吐量和延迟。

抱歉,评论功能暂时关闭!