垃圾收集算法
为什么要有GC
- 自动监测对象是否超过作用域从而达到自动回收内存的目的
Java垃圾回收机制
- Jvm中,有一个垃圾回收线程,它的优先级很低的线程,正常情况下它是不会触发执行的,只有当虚拟机空闲或者内存不足的时候,才会回收没有任何引用的对象
垃圾收集器可以马上回收内存吗?
- 通过system.gc()提醒虚拟机:希望进行一次垃圾回收,但是它不能保证垃圾回收一定会进行。
GC算法
- 标记-清除算法:标记出所有需要回收的对象,在标记完成后统一回收掉所有标记的对象
- 复制算法:将内存划分为大小相等的两块,每次只是用其中一块,当一块用完了,就将还存活着的对象复制到另一块上,然后再把用完的那块一次性清理掉
- 标记-整理算法:标记所有存活的对象,让其移动到一端,然后清理掉这端以外的对象
- 分代收集算法:
新生代:占据堆的1/3空间,分为Eden区(Java新对象的出生地)、ServivorFrom、ServivorTo,比例是8:1:1。采用复制算法垃圾回收,每次回收时都有大量垃圾被回收,
例如:方法的局部变量、相同类型的对象大小大于ServivorFrom空间大小的一半
老年代:堆中,采用标记-清除、标记-整理算法,每次回收时只有少量对象被回收,例如:缓存对象、单例对象、session、spring里的bean。分代年龄到达15后会移入老年代
永久代:存在于方法区中,在Java8中,永久代已经被移除,被“元数据区”所取代。元空间与永久代之间最大的区别在于:元空间并不在虚拟机中,而是使用本地内存
永久代也用标记-清除算法或者标记-整理算法进行垃圾回收
分代收集算法详情
算法存在的问题
- 标记-清除算法:效率不高、会产生大量的内存碎片,导致以后程序在分配较大的对象时没有充足的内存,而提前触发一次GC动作
- 标记-整理算法:移动对象需要成本
对象是否可以被回收
哪些对象可以作为GC Roots对象(见垃圾收集器上方的图)
垃圾收集器
垃圾收集器
- Serial收集器:串行,单线程垃圾收集⼯作的时候必须暂停其他所有的⼯作线程( "StopThe World" ),直到它收集结束
- ParNew收集器:多线程垃圾回收
- CMS收集器:用户线程和垃圾回收线程同时执行,基于标记-清除算法实现
- G1收集器:
空间整合:G1整体基于标记-整理算法实现,局部采用复制算法
可预测的停顿
分代收集
用户线程和垃圾回收线程同时执行
CMS垃圾收集器