java queue 使用 【学习笔记】Java虚拟机(四)垃圾收集与算法(2)

电脑杂谈  发布时间:2018-02-17 15:00:36  来源:网络整理

二、垃圾收集算法

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、分代收集算法

Java的queue怎么入队_java queue 使用_java queue原理

商业虚拟机采用的都是分代收集算法(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

相关阅读
    发表评论  请自觉遵守互联网相关的政策法规,严禁发布、暴力、反动的言论

    热点图片
    拼命载入中...