我们从下面的三件事情开始今天的探讨
1、哪些内存需要回收
2、什么时候进行回收
3、如何进行回收
我们对内存进行回收,我们就要先知道哪些东西可以被我们进行回收,那就是要回收那些已经死去的对象。
如何判断对象已经死去
1、采用 引用计数法
我们对我们在一个地方对对象进行引用的时候,计数器的值就 +1 ,当引用失效的时候进行减一,当计数器为0的时候默认他是可以被回收的对象。
缺点:如果两个都失去引用的对象之间存在互相引用,即他们已经不存在任何引用,但是他们的计数器依旧不为0;
如下
A a = new A(); B b = new B(); a.conf = b; b.conf = a; a= null; b= null;
2、采用 可达分析法(根搜索算法)
我们判断一个对象是否为存活对象就判断他是否有跟 GC Roots 存在引用链,如果有就是存活,没有就凉凉。
什么是GCRoots呢
1、虚拟机栈即栈帧中的本地变量表中的引用的对象。
2、方法区中的类静态属性引用的对象
3、方法区中的常量引用的对象
4、本地方法栈中的引用对象。
在我们判断对象为不可达对象的时候,是否就代表该对象为死亡对象呢
不是的,他会进行如下的步骤。
步骤:
1、被判断为不可达对象。
2、判断该对象有没有执行 finalize 的机会。(判断条件:1、查看该对象是否执行过 finalize方法。2、查看该对象有没有覆盖finalize方法)
3、被判断为有机会的对象,就会进如 队列当中
4、在排队进行 finalize的对象,在过不久的时间会在一次进行一次 Gc 。
我们上面默认讲的都是堆中的内存回收,那么方法区是否会进行回收呢
会的,只是方法区的回收率相对较为低下。
回收内容
1、废弃的常量
回收条件:
如我们定义了 “abc” 这个常量,并且该常量在其他地方没有引用了这个字面量,这个时候就会发生内存回收。
2、无用的类
回收条件:
(1)该类的所有实例都被回收了,也就是在堆中不存在该类的任何实例。
(2)加载该类的ClassLoader 已经被进行回收。
(3)该类对应的 Class 对象没有在任何地方被引用,无法在任何地方通过反射访问该类的方法。
在知道了,何种对象可以被进行回收,那么我们通过何种方式来进行回收的呢
1、标记清除算法
(1)对那些被我们判定为可回收的对象进行标记
(2)进行回收
缺点:(1)效率问题,标记和清除的过程效率不高。(2)清除后会出现大量的内存碎片,导致大对象无法存储,而导致Gc。
2、复制算法
将我们的内存划分为三块区域,默认为 一块 Eden 区域 两块 survivor 区域。这两块也被成为 from 和 to 这两个名字。
过程: 我们将我们新出生的对象存放到 Eden 区 和 一块 survivor 区域,每当进行一个 Gc 的时候,就会把 这两块区域的存活对象移到一块 survivor 区域当中,在将原本的两块的内存清空。如果最后一个survivor内存不足,这时候会出现两种情况:
(1)判断是否有设置分配担保,如果有就把内存移到老年代,没有的情况下 FullGC
(2)如果设置了内存担保就会进入老年代,在进行判断老年代的大小是否满足,如果不满足就会进行一次 FullGC,相反就是为 MinorGC
3、标记整理算法
出现的原因:
复制算法就是使用浪费一部分的内存来进行使用的,但是有一个问题是,当我们想要清理的内存中,该内存的存放区域的存活率较高。所以复制算法并不合适,如老年代就类似该内存。
过程:将存活的对象都向一端进行移动,然后直接清理掉端边界以外的内存。
4、分代收集算法
如上面标志整理算法我们可以得知,所有内存使用相同的方法并不合适,所以建议在 新生代采用复制算法,在老年代使用标志整理算法。
在上面出现的 Full GC 与 MinorGc 的区别
MinorGc:指发生在新生代的垃圾收集动作,因为java 对象大多都具备朝生夕灭的特征,所以这种回收发生得非常频繁,一般回收速度也比较快。
MajorGc/FullGc: 指发生在老年代的Gc,出现这种垃圾回收,经常伴随着出现至少一次的 Minor Gc。
对象优先分配在Eden区域
在大多数情况下,对象在新生代 Eden 区中分配。当没有足够的空间进行分配时,虚拟机将发起一次 Minor Gc。
-XX:+PrintGCDetails 打印垃圾回收日志。
大对象直接进入老年代
-XX:PretenureSizeThreshold 设置当对象大于或等于某个数值的时候直接进入老年代当中。
长期存活的对象进入老年代
-XX:MaxTenuringThreshold 设置经过多少次Gc 该对象如果还存活就会进入老年代当中。
动态对象年龄判定
如果在survivor 空间当中相同年龄所有对象大小的总和大于survivor的一半,就会直接进入 老年代当中
空间分配担保
-XX:HandlePromotionFailure 设置是否进行老年代担保。
如果最后一个内存不足,这时候会出现两种情况:
(1)判断是否有设置分配担保,如果有就把内存移到老年代,没有的情况下 FullGC
(2)如果设置了内存担保就会进入老年代,在进行判断老年代的大小是否满足,如果不满足就会进行一次 FullGC,相反就是为 MinorGC