java垃圾收集器概述
背景
java语言作为后起之秀,解决了以前手动管理内存的问题,这里面一个重要的东西就垃圾回收器,虽然开发人员不用关心内存分配问题了,但是线上运行的系统可能会有各种未知的问题,如有内存溢出、频繁的full gc等等,这里面就涉及到一些参数调整,如果不对垃圾回收器有个大概的了解,处理起来也很棘手。
回收前置条件
判断对象是否可回收?
1.引用计数算法
当某个对象的引用数量大于0时才是存活的,一旦引用数量为0就可以回收,java虚拟机没使用这种算法,不做解释,想研究算法的可参考《垃圾回收算法手册 自动内存管理的艺术》第五章节。
2.可达性分析算法
Hotspot虚拟机就采用此算法,如下图:
在 Java 中 GC Roots 一般包含以下内容:
- 虚拟机栈中引用的对象
- 本地方法栈中引用的对象
- 方法区中类静态属性引用的对象
- 方法区中的常量引用的对象
3.finalize()方法
如果进行可达性分析回收之后,有执行finalize()方法,相当于对象发出一次自救行为,系统也自会自救一次,如果下次垃圾回收还是会把此对象回收掉。
4.常量池的回收条件:
- 该类所有的实例都已经被回收,也就是Java堆中不存在该类及其任何派生子类的实例。
- 加载该类的类加载器已经被回收。
- 该类对应的java.lang.Class对象没有在任何地方被引用,无法在任何地方通过反射访问该类的方法。
引用类型
强引用:如Object obj=new Object(),无论任何情况下,只要强引用关系还存在,垃圾收集器就永远不会回收掉被引用的对象。
软引用:在系统将要发生内存溢出异常前,会把这些对象列进回收范围之中进行第二次回收,如果这次回收还没有足够的内存,才会抛出内存溢出异常,使用SoftReference实现。
弱引用:被弱引用关联的对象只能生存到下一次垃圾收集发生为止。当垃圾收集器开始工作,无论当前内存是否足够,都会回收掉只被弱引用关联的对象,使用WeakReference实现。
虚引用:最弱的一种引用关系,为一个对象设置虚引用关联的唯一目的只是为了能在这个对象被收集器回收时收到一个系统通知,使用PhantomReference实现。
垃圾回收算法
- 分代收集理论
如图所示,堆空间里面,大部分对象的生命周期都很短暂,java虚拟机针对不同的分代,采用了不同的垃圾算法。
- 标记-清除算法
标记可回收对象,然后统一清除。缺点:1)执行效率不稳定,如果有大量对象需要回收,需要大量的标记清理;2)会产生大量不连续的内存碎片,导致无法给大对象分配内存。
- 标记-复制算法
将可用内存按容量划分为大小相等的两块,每次只使用其中的一块。当这一块的内存用完了,就将还存活着的对象复制到另外一块上面,然后再把已使用过的内存空间一次清理掉。缺点:只是用了一半的内存。
- 标记-整理算法
让所有存活的对象都向内存空间一端移动,然后直接清理掉边界以外的内存。
垃圾收集器
使用-XX JVM参数对应的垃圾收集器:
UseSerialGC:Serial + Serial Old;
UseParNewGC:ParNew + Serial Old;
UseConcMarkSweepGC:ParNew + CMS + Serial Old,Serial Old只是当CMS收集失败了备用的一个选择;
UseParallelGC:Parallel Scanvenge + Serial Old;
UseParallelOldGC:Parallel Scanvenge + Parallel Old;
UseG1GC:G1。
参考资料:
Java Platform, Standard Edition HotSpot Virtual Machine Garbage Collection Tuning Guide