1、标记-清除算法
分为两步:标记-->清除
1.1、标记:遍历所有的GC Roots,然后将所有的GC Roots可达的对象标记为存活的对象(下文mark=1已标记,mark=0未标记)
1.2、清除:清除的过程将遍历所有堆中的对象,将没有标记的对象(mark=0)全部清除掉
总结:在程序运行过程中,当可用内存被消耗待尽的时候,GC线程就会被处罚并将程序暂停,随后将GC Roots可达的对象标记为1,最后将堆中所有没有标记为1的对象全部清除掉,恢复程序运行,GC Roots可达的对象标记重新置为0;
缺点:
效率低(递归与全堆对象遍历),而且在进行GC的时候,需要停止引用程序,这会导致用户体验非常差劲,尤其对于交互式的应用程序来说,简直是灾难。试想一下,你逛了3分钟淘宝,然后就挂了,那电子商务就不会发展到现在了
清理出来的空闲内存是不连续的,怎么来理解一下呢,就是我们“死亡”的对象会随机的出现在内存的各个角落里,把它们清除了之后,内存的布局自然会是不连续的。为了应付这个问题,JVM就必须维持一个内存的空闲列表,当分配一个比较的数组时(大到没有连续的内存空间)
2、复制算法
复制算法将内存分为两个区间,这两个区间是动态的,在任意一个时间点,所有分配的对象内存只能在其中一个区间(活动区间),另外一个区间就是空闲区间
当有效内存空间耗尽时,JVM将暂停程序运行,开启复制算法GC线程。GC线程会将活动区间内的存活对象,全部复制到空闲区间,且严格按照内存地址依次排列,与此同时,GC线程将更新存活对象的内存引用地址指向新的内存地址。这个时候空闲内存已经变成了活动区间,垃圾对象全部在原来的活动区间,清理掉垃圾对象,原活动区间就变成了空闲区间。
1.内存即将耗尽为复制之前状态
2.复制之后
优点:
很好地解决了标记-清除算法,内存布局混乱的缺点
缺点:
浪费一半的内存
假设对象存活率为100%,那么复制算法的GC过程就是重复的把对象复制一遍,而且将所有的引用地址重置一遍。可以预见的复制所消耗的时间随着对象存活率达到一定程度将会变成灾难。所以复制算法使用的场景是可以忍受只是用50%内存,对象存活率非常低
3、标记-整理算法
标记-整理算法分为两个阶段:1.遍历GC Roots可达的对象,标记为已存活,如果不可达标记为未存活;2.将已存活的对象按照顺序排列在内存中,修改新的地址,将末端内存以后的对象清除掉
优点:
弥补了标记-清除算法,内存区域分散的缺点
弥补了复制算法内存减半的代价
缺点:
效率不高,对于标记-清除而言多了整理工作,对于复制算法而言多了标记工作
标记-清除/复制/标记-整理算法