美团面试题:JVM的年轻代是怎么设计的?
1、JVM中的堆,一般分为三个部分,新生代、老年代和永久代。这个是你第一天学JVM就知道的。但你可以先想想,为什么需要把堆分代?不分代不能完成他所做的事情么?
2、是这样,如果没有分代,那我们所有的对象都在一块,GC 的时候就要先找到哪些对象没用,怎么找呢?没分代就得对堆的所有区域进行扫描。但你知道,很多Java对象都是朝生夕死的,如果分代的话,我们可以把新创建的对象放到某一地方,GC的时候就可以迅速回收这块存“朝生夕死”对象的区域。
3、所以,一句话总结,分代的唯一理由就是优化 GC 性能。你这么记,就容易把知识串起来了。
4、HotSpot JVM 把年轻代分为了三部分:1 个 Eden 区和 2 个 Survivor 区(分别叫from 和 to),他们的默认比例为 8:1。一般情况下,新创建的对象都会被分配到 Eden区,这些对象经过第一次 Minor GC 后,如果仍然存活,将会被移到 Survivor 区。对象在 Survivor 区中每熬过一次 Minor GC,年龄就会增加 1 岁,当它的年龄增加到一定程度时,就会被移动到年老代中。这是一个对象的生存路径。
5、因为年轻代中的对象基本都是朝生夕死的( 80% 以上),所以在年轻代的垃圾回收算法使用的是复制算法,复制算法的基本思想就是将内存分为两块,每次只用其中一块,当这一块内存用完,就将还活着的对象复制到另外一块上面。复制算法不会产生内存碎片。
6、在 GC 开始的时候,对象只会存在于 Eden 区和名为“ From ”的 Survivor 区,Survivor 区“To”是空的。紧接着进行 GC,Eden 区中所有存活的对象都会被复制到“To”,而在“From”区中,仍存活的对象会根据他们的年龄值来决定去向。
7、年龄达到一定值(可以通过-XX: MaxTenuringThreshold来设置)的对象会被移动到年老代中,没有达到阈值的对象会被复制到“To”区域。经过这次 GC 后,Eden 区和From 区已经被清空。这个时候,“From”和“To”会交换他们的角色,也就是新的“To”就是上次 GC 前的“From”,新的“From”就是上次 GC 前的“To”。不管怎样,都会保证名为 To 的 Survivor 区域是空的。
8、Minor GC 会一直重复这样的过程,直到“To”区被填满,“To”区被填满之后,会将所有对象移动到年老代中。注意,我说的是 Minor GC,不是 Full GC,这俩的关系你要缕清楚。
9、好记吗?不好记,我再给你做个类比。我叫小强,是一个普通的 Java 对象,我出生在Eden 区,在 Eden 区我还看到和我长的很像的小兄弟,我们在 Eden 区中玩了挺长时间。有一天 Eden 区中的人实在是太多了,我就被迫去了 Survivor 区的“From”区,自从去了 Survivor 区,我就开始漂了,有时候在 Survivor 的“From”区,有时候在 Survivor 的“To”区,居无定所。直到我 18 岁的时候,爸爸说我成人了,该去社会上闯闯了。于是我就去了年老代那边,年老代里,人很多,并且年龄都挺大的,我在这里也认识了很多人。在年老代里,我生活了20年(每次GC加一岁),然后去世了。
10、年轻代的JVM参数也不多,我给你列出来了,你也不用记,用着多了自然就熟悉了。
总而言之,JVM 内存问题排查需要掌握一定的技巧,而这些技巧并不是我告诉你,你就会用的,更重要的还是需要在实战中去应用。
扫码报名哈