共计 974 个字符,预计需要花费 3 分钟才能阅读完成。
标记革除算法
当堆中的无效空间被耗尽时,JVM 就会进行整个程序 (也被称为 stop the world), 而后开始两项工作. 一是:
标记
, 而是:革除
标记
遍历所有 GC Roots, 将所有 GC Roots 可达的对象都标记为存活对象.
革除
遍历堆中所有的对象把没有标记的对象全副革除.
在程序运行期间, 当堆中的可用内存被耗尽时,GC 线程就会启动并进行程序,GC 线程将存活的对象标记一遍, 没有被标记的对象就是垃圾对象, 最初这些垃圾对象会被革除掉, 而后从新唤醒应用程序.
程序运行时堆中对象的状态(默认为 0 未标记,1 为标记过), 如果堆内存的可用空间被耗费完, 那么 GC 线程就会启动, 进行掉应用程序, 应用根可达性算法进行搜寻标记.
被标记后的对象状态
应用根可达性算法, 所有 GC Roots 可达的对象都被标记为存活对象, 此时曾经实现了第一阶段的工作. 接下来执行革除操作, 执行完革除操作, 堆中对象的状态.
没有标记的对象被革除, 被标记的对象会被留下, 标记为被置为 0, 应用程序被唤醒.
标记革除的长处是算法简略, 毛病如下:
1. 效率低下, 须要遍历整个堆. 进行 GC 的时候须要进行应用程序
2. 垃圾回收后的内存空间是不间断的, 因为垃圾对象的散布很随便, 那么革除后的内存会不间断. 为了解决这个问题,JVM 不得不保护一个闲暇链表, 又会导致额定的开销.
复制算法
复制算法应用了两块等同大小的内存空间, 每次只用一块, 垃圾回收的时候, 把存活的对象间接另外一块内存, 而后残余的垃圾对象全副一次性革除. 益处是复制存活对象的时候就不必思考内存碎片. 惟一的毛病就是内存利用率只有 50%.
当初的虚拟机个别都用复制算法回收新生代,IBM 的钻研发现, 新生代中的对象 98% 都是朝生夕死, 所以并不需要 1:1 调配对象, 而是将内存分为一个大的 Eden 和两块小的 Survivor 空间, 每次只应用 Eden 和一块 Survivor. 当进行垃圾回收时, 将存活对象一次性复制到一块 Survivor 空间, 最初革除掉 Eden 和应用过的 Survivor 空间. HotSpot 虚拟机 Eden:Survivor=8:1, 也就新生代可用的内存达到 90%, 只会有 10% 的节约. 当然 98% 的对象可被回收只是个别的场景, 并没有方法保障每次 Survivor 都能寄存的下存活对象, 若 Survivor 空间不够时, 须要依附老年代进行调配担保.
from ,to 为 Survivor 区。