什么时候会出发垃圾回收

系统运行创建对象是优先分配在新生代里面的,当新生代里面对象越来越多,此时就会出发垃圾回收,把新生代没有人引用的对象给回收掉,释放内存空间

被那些变量引用的对象不能够被回收

jvm使用可达性分析算法判断哪些对象是可以被回收的,哪些对象是不可以被回收的(每个对象,都分析一下有谁在引用他,然后一层一层往上去判断,看是否有一个GC Roots)。

java对象中不同对象的引用类型

强引用、软引用、弱引用、虚引用。
强引用: static ReplicaManage replicaManage = new ReplicaManage(); 一个对象如果是强引用,那么他绝对不会被回收
软引用: 就是实例对象把用一个“SoftReference” 包裹起来, 此时这个“replicaManager” 变量对“ReplicaManager对象的引用就是软引用了。正常情况下垃圾回收是不会回收软引用对象的,但是如果进行垃圾回收之后发现内存空间还是不够存放新的对象,内存快溢出了,此时就会把这些软引用对象给回收掉。
public static SoftReference replicaManage = new SoftReference(new ReplicaManager());
弱引用:弱引用如果发生垃圾回收就会被回收掉
虚引用:发生垃圾回收时会被回收掉

finalize()方法的作用

当一个对象要被垃圾回收时,此时会尝试条用一下他的finalize(),看是否把自己这个实例对象给了某个GC roots,比如代码中就给了ReplicaManager类的静态变量,如果重新让某个GC roots变量引用自己,那么就不会被垃圾回收

复制算法

针对新生代的垃圾回收算法,它叫做复制算法。首先把新生代的内存分为块,然后只使用一块内存,待那块内存快满的时候,就把里面的存活对象一次性装一到另一块区域,保证没有内存碎片。接着一次性回收原来那块内存的垃圾对象,再次空出来一块内存区域。两块内存区域就这么重复循环使用。
先对那块在使用的内存空间标记出里面那些对象是不能进行垃圾回收的,就是要存活的对象,然后把那些存活的对象转移到另一块空白的内存中(可以比较紧凑的使用内存,避免造成内存碎片,浪费内存空间)。

复制算法缺点

从始至终,就只有一半的内存可以使用,这样的算法显然对内存的使用效率太低了。

复制算法优化

实际上真正的复制算法,会把新生代区域划分为1个Eden区、2个Survivor区。其中Eden区默认占80%,每一块Survivor区各占10%。平时可使用Eden区和其中一块的Survivor区。,如果Eden区域快满了,此时就会触发垃圾回收,把Eden中存活的对象一次性转移到另一个Survivor区域。接着Eden就会被请客,然后再次分配对象到Eden区,Eden区域和一块Survivor区域里是有对象,其中Survivor区里放的是上一次Minor GC存活的对象,如果下次Eden区域满时,那么会再次出发minor GC,就会把Eden区和放着上一次MinorGC 后的survivor区域内存活对象转移到另一块Survivor区去。这样最大的好处使得复制算法只有10%。提升了垃圾回收性能,内存碎片控制,还有内存使用率。

新生代进入老年带的触发条件

  1. 在新生代中每经历1次Minor GC年龄就会+1 当躲过15Minor GC时就会进入老年带 —XX:MaxTenuringThreshold 来设置
  2. 动态年龄对象:如果一次新生代gc过后,发现survivor区域中的年龄的对象加起来超过Survivor区域的50%,比如年龄1+年龄2+年龄3的对象大小总和,超过了survivor区域50%,那么就会把年龄3以上的对象都放入老年代
  3. 大对象会直接进入老年带:—XX:PretenureSizeThreshold 来设置字节数
  4. Minor GC 后对象无法放入Survivor区域也会直接进入老年带

老年代空间分配担保规则

在执行Minor GC 之前,JVM会检查一下老年代大的可用的内存空间,是否大于新生代所有对象的总和,如果大于,就会对新生代发起一次Minor GC,如果Survivor区域放不下就可以转移到老年带去。如果新生代对象 > 老年代空间。会查看-XX:HandlerPromotionFailure参数是否设置。然后继续尝试下一步,看看老年代的内存大小,是否大于之前每一次Minor GC后进入老年代的对象的平均大小。如果失败或者没有设置XX:HandlerPromotionFailure,此时就会触发Full GC.(对老年带进行垃圾回收,同时也对新生代进行垃圾回收),如果还是不足够就会OOM

老年代Full GC规则

  1. 在Minor GC之前,一通检查发现很可能Minor GC之后要进入老年代的对象太多了,老年代放不下,此时需 要提前触发Full GC然后再带着进行Minor GC
  2. 在Minor GC之后,发现剩余对象太多放入老年代都放不下了

老年代GC算法
标记整理算法:对存活对象进行标记,然后整理紧凑,避免垃圾回收过后出现内存碎片。然后一次性回收掉所有对象。老年代垃圾回收算法比新生代回收算法慢10倍。因此full GC 非常影响性能。
所谓JVM优化就是尽可能的让对象都在新生代里面被分配回收。避免进入老年代触发Full GC ,同时给系统充足的内存大小,避免新生代被频繁的垃圾回收。

思考:

1.什么时候回尝试触发Minor GC
2.触发Minor GC 之前会如何检查老年代的大小,涉及那几个步骤
3.什么时候在Minor GC之前就会提前出发一次Full GC
4.Full GC 算法是什么
5.Minor GC过后可能对应哪几种情况
6.哪些条件下 Minor GC后的对象会直接进入老年代

触发Full GC

1.每次Minor GC之前都会检查下 老年代可用内存空间 < 历次Minor GC后升入老年代平均对象大小
2.可能末次Minor GC 后要升入老年代的对象有几百MB,但是老年代空间不足
3.设置了 -XX:CMSlnitiatingOccupancyFaction 参数,比如设定值为92%,那么此时可能前面几个条件都没有满足,但是刚好发现这么条件满足了,老年代使用空间超过了百分之92%,此时会自行出发Full GC