以整理为XMind,方便阅读欢迎下载
为什么回收, 哪些需要回收
如果不进行垃圾回收, 内存迟早都会被消耗空, 因为我们在不断的分配内存空间而不进行回收. 除非内存无限大, 我们可以任性的分配而不回收, 但是事实并非如此. 所以, 垃圾回收是必须的
不可能再被任何途径使用的对象
常见标记方法
引用计数法
给对象中添加一个引用计数器
每当一个地方引用这个对象时, 计数器值+1;当引用失效时, 计数器值-1
任何时刻计数值为0的对象就是需要被清理的
弊端
不能清理两个相互引用的对象
可达性分析法
以GC Roots的对象为起点
从这些节点向下搜索, 搜索所走过的路径称为引用链
当一个对象到GC Roots没有任何引用链即GC Roots到对象不可达
任何不可达对象都是需要被清理的
回收前提
对于可达性分析算法而言,未到达的对象并非是“非死不可”的,若要宣判一个对象死亡,至少需要经历两次标记阶段。
如果对象在进行可达性分析后发现没有与GCRoots相连的引用链,则该对象被第一次标记并进行一次筛选
finalize
根据是否执行过finalize方法,没执行的排队执行,执行过得清除
引用状态
JDK1.2之前
引用
非引用
在JDK1.2之前, Java中引用的定义很传统: 如果引用类型的数据中存储的数值代表的是另一块内存的起始地址, 就称这块内存代表着一个引用. 这种定义很纯粹, 一个对象只有被引用或者没被引用两种状态. 我们希望描述这样一类对象: 当内存空间还足够时, 则能保留在内存中; 如果内存空间在进行垃圾收集后还是非常紧张, 则可以抛弃这些对象. 很多系统的缓存功能都符合这样的应用场景. 在JDK1.2之后, Java对引用的概念进行了扩充, 将引用分为: 强引用,软引用,弱引用,虚引用4种,这4种引用强度依次减弱
JDK1.2之后
四种引用状态
强引用
强引用,不进行垃圾回收,如Object obj=new Object
软引用
软引用,有用非必须对象,在内存溢出前进行回收,SoftReference
弱引用
弱引用,非必须对象,只能生存到下次垃圾收集时,WeakReference
虚引用
虚引用,无用对象,垃圾收集时会收到系统通知,PhantomReference
方法区的垃圾回收
废弃常量
没有任何一个Spring对象引用的常量,且发生必要清除的时候才会被回收
无用的类
该类的所有实例都已经被回收
该类对应的java.lang.Class对象没有在任何地方被引用
加载该类的ClassLoader已经被回收
垃圾收集算法
标记-清除(Mark-Sweep)算法
过程
分为“标记”和“清除”两个阶段
首先标记出所有需要回收的对象
标记完成后统一回收所有被标记的对象
缺点
内存碎片化
需要分配较大对象时不得不提前触发一次垃圾收集动作
复制(Copying)算法
过程
将可用的内存分为两块
每次只用其中一块, 回收时将还存活着的对象复制到另外一块上面
然后再把已经使用过的内存空间一次性清理掉
缺点
内存缩小为了原来的一半
标记-整理(Mark-Compact)算法
过程
让所有存活对象都向一端移动
然后直接清理掉边界以外的内存
缺点
复制算法在对象存活率较高的场景下要进行大量的复制操作,效率很低
分代收集算法(现代商用虚拟机基本都采用)
上面内容的结合体
逻辑
根据对象的生命周期的不同将内存划分
然后根据各块的特点采用最适当的收集算法
实践
大批对象死去,少量对象存活的(新生代),使用复制算法,复制成本低
对象存活率高, 没有额外空间进行分配担保的(老年代),采用标记-清理算法或者标记-整理算法