常见的GC算法:
-
复制
-
标记清除
-
标记整理(标记压缩)
一:复制算法
复制算法详情:已知在堆内存中存在新生代和老年代,其中新生代中又存在着伊甸区、幸存者0区、幸存者1区,每一次轻GC过后伊甸区的内存会被清空,仍然存活着的数据会被移交给幸存者区,当然幸存者区是双向流动的,也就是常见的form 和 to,to区默认是为空的一方,幸存者区的GC会将from区的内容移交给空的to区域,然后此时的to区域就会转换为from区域,以此类推,假如经过了15次(默认值)轻GC后对象仍然能够存活,那该数据才会被移交给老年区,当然15次的这个默认值也是也可调节的。
复制算法在对象存活度较低的场景中使用,常见于新生代。
优点:两个区像玻璃烧瓶的液体一样倒过来倒过去,不存在内存碎片
缺点:因为要保证幸存者to区必须为空,因此内存折半
二:标记清除算法
详情:GC时会优先对内存中的对象进行一次扫描,然后把仍然存活着的对象进行标记,第二次扫描时会清除那些没有被标记的对象。
算法有点类似于俄罗斯方块,处在同一水平线上的方块会被清除,但后续压下来的方块(存活对象)之间则很容易产生间隙。
优点:不用折损内存
缺点:两次扫描,时间成本高;只清除没有被标记的对象会产生大量零碎的内存碎片
三:标记压缩
详情: 相较于标记清除后再增加的一次扫描,这一次的扫描会把活着的对象直接怼到一旁,从而防止内存碎片的产生。
优点: 解决了产生内存碎片的问题
缺点: 增加了一个移动对象的成本
四:分带搜集算法
即GC,本质上不能说是算法,反倒更像是在强调一种算法使用的方式和规则。
为了更好的物尽其用,GC在年轻代中强调使用复制算法,在老年代中强调使用标记清除和标记压缩算法。
年轻代中对象存活率极低,因此可以使用时间复杂度较低的复制算法来实现效率的最大化。
而在老年代中对象存活率很高,尽管标记压缩算法在内存处理上算是最优解,但一开始就使用压缩并搬移对象所产生的成本依然不是很划算,因此需要先使用标记清除算法,在算法使用完一定次数过后,内存碎片开始出现,这时候才需要使用标记压缩对内存碎片进行一下整理,以此达到相对优异的处理的状态。
当然,根据实际项目的具体情况的不同,在JVM调优的时候也会对算法的使用次数和使用限制进行一下具体的参数设定和配置。