Java — 关于垃圾收集灵魂拷问三连(三)
前言
这是本系列的最后一篇,主要讲解内存分配策略。在上一篇文章中,我们已经介绍了堆内存的分配区域,分为三种:新生代、老年代和持久代。而持久代对垃圾回收没有太大影响,所以在之后讨论基于分代算法的垃圾收集器是按新生代和老年代划分的。
Java技术体系中所提倡的自动内存管理最终可以归结为自动化了解决了两个问题:给对象分配内存和回收分配给对象的内存。对于内存回收、内存分配,之前都已经说过了,下面在深入一下内存分配,介绍内存分配策略。
内存分配策略主要有以下三点:
- 对象优先在Eden分配
- 大对象直接进入老年代
- 长期存活的对象将进入老年代
下面分别介绍这三个分配策略。
对象优先在Eden分配
大多数情况下,对象在新生代Eden区分配。当Eden区没有足够的空间分配时,虚拟机将发起一次Minor GC。
那么Minor GC和之前提到的Full GC有什么区别吗?
新生代GC(Minor GC)
指发生在新生代的垃圾收集,因为Java对象大多都具备朝生夕灭的特性,所以Minor GC非常频繁,一般回收速度也比较快。
老年代GC(Major GC / Full GC)
指发生在老年代的GC,出现了Major GC,经常会伴随至少一次的Minor GC(并非绝对),Major GC的速度一般会比Minor GC慢十倍以上。
大对象直接进入老年代
所谓大对象是指,需要大量连续内存空间的Java对象,最典型的大对象就是那些很长的字符串以及数组。大对象对虚拟机的内存分配来说是一个坏消息(比遇到一个大对象更恐怖的是遇到一个朝生夕灭的短命大对象),经常出现大对象容易导致内存还有不少空间时就提前触发垃圾收集以获取足够的连续空间来安置它们。
长期存活的对象将进入老年代
虚拟机既然采用了分代收集的思想来管理内存,那么内存回收就必须能识别哪些对象应该放在新生代,哪些对象放在老年代。为了做到这一点,虚拟机给每个对象定义一个对象年龄计数器。如果对象在Eden出生并经过一次Minor GC后仍然存活,并且能被Survivor容纳的话,将会被移动到Survivor空间,并将对象年龄加一。对象每在Survivor区熬过一次Minor GC,年龄就增加一,当它的年龄增加到一定程度时(默认是15),就会被晋升到老年代。
最后
到这里,灵魂拷问三连就结束啦,完结撒花 ~~~ 开心。
期间,要感谢《深入理解Java虚拟机》的作者 — 周志明,还有在简书上看到的两篇非常nice的博文:
https://www.jianshu.com/p/5261a62e4d29
https://www.jianshu.com/p/a67c3fdcc8e8
感谢以上作者。
在这个知识分享的时代,你没有任何理由感到惶恐焦虑!