二、垃圾收集算法
1、标记-清除算法
标记-清除算法(Mark-Sweep)是最基础的算法,首先标记出需要回收的对象,然后统一回收。它
的缺点是效率较低,回收后内存空间零散,空间碎片多,在分配大内存需求时无法找到足够的连续内
存导致触发另一次垃圾收集动作。
2、复制算法
复制算法(Copying)会将可用内存按容量划分为大小相等的两块,每次使用其中一块,当这块用完
后就将仍存活的对象复制到另一块上,然后把之前的内存空间全部清理掉。缺点是要将内存可用空间
缩小为一半。但现在的商业虚拟机都采用这种算法回收新生代,但并不是1:1比例划分内存空间,而是
分为一块较大的Eden和两块较小的Survivor空间,每次使用Eden和Survivor中的一块,回收时把所有
存活对象复制到另一个Survivor上,最后清理掉Eden和之前的Survivor。HopSpot默认Eden与
Survivor的大小比例是8:1,当Survivor空间不够用时,就需要依赖其他内存(老年代)进行分配担保
(Handle Promotion),直接分配到担保区域中。
3、标记-整理算法
根据老年代的特点,一般使用标记-整理算法(Mark-Compact),标记过程与标记-清除算法一样
,之后将所有存活对象向一端移动,最后清理掉端边界外的内存。
4、分代收集算法

商业虚拟机采用的都是分代收集算法(Generational Collection),根据对象存活周期的不同将内存
划分为几块,一般就是新生代与老年代,然后针对各个年代的特点选用不同的收集算法,例如新生代
选用复制算法,老年代选用标记-清除或标记-整理算法。
5、HotSpot的算法
① 枚举根节点
为了保证可达性分析的一致性,GC在枚举根节点时要停止所有线程(Stop The World)以确
定在执行期间不会有新的引用关系发生。在停止时,HotSpot不需要检查所有执行上下文和全
局的引用位置,它使用了一组称为OopMap的数据结构来达到目的,在类加载完成的时候就已
经把对象内什么偏移量上是什么类型的数据计算出来了,JIT编译过程中也会在特定的位置记
录下栈和寄存中哪些位置是引用,所以GC时就可以直接得知这些信息了。
② 安全点
如果为每一条指令都生成OopMap数据,将会占用大量的额外空间,提高了GC的时间成本。
所以HotSpot没有这么做,它只是在特定的位置记录了这些信息,这些位置称为安全点
(Safepoint),程序执行时只有在到达安全点时才可以暂停开始GC。安全点的选定标准就是
“是否具有让程序长时间执行的特征”,“长时间执行”最明显的特征就是指令序列服用,例如方
法调用、循环跳转、异常跳转等。
在GC发生时,我们要将所有线程都跑到安全点上后才可以停顿下来。有两种方案可以选择:
● 抢先式中断(Preemptive Suspension):在GC发生时首先把所有线程中断,如果
发现有线程中断的地方不再安全点上,就恢复线程直到它执行到安全点上。现在几乎没
有虚拟机采用这种方式。
● 主动式中断(Voluntary Suspension):在GC需要中断线程时设置一个标志,各个
线程执行时主动轮询该标志,发现中断标志为真时就自己中断挂起,轮询标志的地点和
安全点是重合的,另外再加上创建对象需要分配内存的地方。
③ 安全区域
当线程处于Sleep状态或Blocked状态时,这时候它无法响应JVM的中断请求并执行到安全点
去挂起,所以需要安全区域(Safe Region)来解决。安全区域是指在一段代码片段中,引用
关系不会发生变化,区域内任何地点开始GC都是安全的。java queue 使用
程执行到安全区域中的代码时,首先标示自己进入安全区,所以GC时就不用再关注这些
线程了,当线程要离开安全区时,它要检查系统是否已经完成了枚举根节点(或者是整个GC
过程),如果完成了,线程继续进行,反之就要等待其完成后再离开安全区。
本文来自电脑杂谈,转载请注明本文网址:
https://www.pc-fly.com/a/jisuanjixue/article-82147-2.html
很真实
可怜的伊拉克连反恐的自由也没有了