GC需要完成的3件事情:
哪些内存需要回收?
什么时候回收?
如何回收?
如何怕暖对象已经死去、
1、引用计数算法(无法解决循环引用的对象需要回收的问题)
引用计数器:给对象添加一个引用计数器,当有房引用它的时候就计数器值加1,否则就建议,当计算器为0的时候对象不能再使用,这种不可行,商用不可用,循环引用的对象需要被清除,无法解决
2、可达性分析算法
通过对一些列称为GC ROOTs对象作为起始点,从这些节点开始往下搜索,搜索走过的路径称为引用连,当一个对象到GC roots没有任何引用能够引用到,则证明此对象不可用,被判定为可回收对象。
可作为GC Roots的对象包括下面集中
虚拟机栈
方法区中类静态属性引用的对象
方法区中常量引用的对象
本地方法栈中JNI(native方法)引用的对象
强引用,软引用,弱引用,虚引用
生存还是死亡?
当对象被判定为不可达对象的时候并非非死不可,处于缓刑阶段,宣告对象死亡至少经理两次标记过程,
第一次标记并且进行一次判定是否执行finalize()方法,如果该方法成功拯救自己,就不会被回收,否则执行完该方法之后如果再次被标记为不可达就需要被回收。(建议忘掉这个方法的存在)
回收方法区,一个类需要满足3个条件才能算是无用的类
该类的所有的实例都已经被回收,也就是java堆中不存在该类的任何实例
加载该类的classloader已经被回收
该类对应的java.lang.class对象没有在任何地方呗应用过
满足上述三个条件的无用类进行回收(可以进行)
垃圾收集算法
标记-清除算法
1)首先标记出所有需要回收的对象(可达性分析算法进行标记)
2)统一回收效率不高,空间碎片问题
复制算法:
1)将对内存分为三个部分,eden ,from, to ,每次新建对象在eden,将还活着的eden,和from survior中的还活着的对象放到 to survivor中去,清理to surviror内存,将from 和 to的地位交换重复上述操作。
标记整理:
对老年代进行垃圾回收不适合使用复制算法,而是采用标记整理算法,标记的过程和可达性分析的算法一样,但是在整理的时候,将所有存货额对象向一端移动,清理掉边界以外的内存
分代收集算法:
将堆内存空间划分为新生代和老年代,根据不同的年代的特点采用适当的收集算法。在新生代中,使用复制算法,老年代采用标记清理算法。
垃圾回收切入时间点:(线程停顿)
枚举根节点
安全点(达到安全点才能够暂停,进行可达性分析)
安全区域(在安全的区域内进行gc,这部分的区域引用关系没有发生变化)
可达性分析对执行---必须在一个额能够确保一致性快照中进行,这里的一致性表示真个分析期间执行系统看起来就像是被冻结在某个时间点上,不可以出现分析过程中对象引用关系还在不同的变化的情况
主流的java虚拟机使用精准gc,有办法得到执行上下文和全局的引用个位置,oopmap的数据结构来达到这个目的。
内存分配与回收策略(进行参数调节)
1)对象优先在Eden分配
2)大对象直接进入老年代
大对象是一个坏消息,比遇到一个大对象更加坏的消息就是遇到一群朝生夕死的大对象
3)长期存活的对象将进入老年代
4)动态对象年龄判断
5)空间分配的安保