面向面试编程:JVM垃圾回收机制

111 阅读4分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第12天,点击查看活动详情

面试官:讲讲JVM的垃圾回收机制

我们在Java堆内存里创建的对象,都是占用内存资源的,而且内存资源有限。

JVM本身是有垃圾回收机制的,他是一个后台自动运行的线程。这个线程会在后台不断检查JVM堆内存中的各个实例对象,如果某个实例对象没有任何一个方法的局部变量指向他,也没有任何一个类的静态变量,包括常量等地方在指向他。那么这个垃圾回收线程,就会把这个没人指向的实例对象给回收掉,从内存里清除掉,让他不再占用任何内存资源。这样的话,这些不再被人指向的对象实例,即JVM中的“垃圾”,就会定期的被后台垃圾回收线程清理掉,不断释放内存资源。

JVM内存分代模型

年轻代、老年代、永久代。大部分对象都是存活周期极短的,少数对象是长期存活的。

面试官:为什么要分成年轻代和老年代?

因为跟垃圾回收有关,对于年轻代里的对象,他们的特点是创建之后很快就会被回收,所以需要用一种垃圾回收算法,对于老年代里的对象,他们的特点是需要长期存在,所以需要另外一种垃圾回收算法,所以需要分成两个区域来放不同的对象。

面试官:什么是永久代?

JVM里的永久代其实就是我们说的方法区。其实所谓的永久代,可以认为永久代就是放一些类信息的。

对象在JVM内存中的分配

平时代码中创建的对象,一般分为两种:

一种是短期存活的,分配在JVM堆内存中,迅速使用完就会被垃圾回收。另外一种是长期存活的,需要一直生存在JVM堆内存里,让程序后续不停的去使用。

第一种短期存活的对象,是在Java堆内存的新生代里的。第二种长期存活的对象,是在Java堆内存的老年代里的。大部分正常对象都优先在新生代分配内存。

面试官:什么情况下会触发垃圾回收?

一个比较常见的场景可能是这样的,假设我们写的代码中创建了N多对象,然后导致Java堆内存里囤积了大量的对象。然后这些对象都是之前有人引用,比如各种各样的方法中的局部变量,但是现在也都没人引用了。这个时候,如果新生代我们预先分配的内存空间,几乎都被全部对象给占满了!此时假设我们代码继续运行,他需要在新生代里去分配一个对象,怎么办?发现新生代里内存空间都不够了!这个时候,就会触发一次新生代内存空间的垃圾回收,新生代内存空间的垃圾回收,也称之为“Minor GC”,有的时候我们也叫“Young GC”,他会尝试把新生代里那些没有人引用的垃圾对象,都给回收掉。

长期存活的对象会躲过多次垃圾回收

如果一个实例对象在新生代中,成功的在15次垃圾回收之后,还是没被回收掉,就说明他已经15岁了。这是对象的年龄,每垃圾回收一次,如果一个对象没被回收掉,他的年龄就会增加1。所以如果对象在新生代中成功躲过10多次垃圾回收,成为一个“老年人”,那么就会被认为是会长期存活在内存里的对象。然后他会被转移到Java堆内存的老年代中去,顾名思义,老年代就是放这些年龄很大的对象。

面试官:老年代会垃圾回收吗?

答案是肯定的,因为老年代里的对象也有可能随着代码的运行,不再被任何人引用了,就需要被垃圾回收。

对象分配的复杂机制

  • 新生代垃圾回收之后,因为存活对象太多,导致大量对象直接进入老年代;
  • 特别大的超大对象直接不经过新生代就进入老年代;
  • 动态对象年龄判断机制;
  • 空间担保机制;