java 面试知识点笔记(四)垃圾回收 上篇

问:对象断定为垃圾的标准?java

没有被其余对象引用算法

问:对象断定为垃圾的算法?线程

引用计数算法3d

  • 经过判断对象的引用数量来判断对象是否能够被回收
  • 每一个对象实例都有一个引用计数器,被引用则+1,完成引用-1
  • 任何引用计数为0的对象实例能够当垃圾收集的

    优势:执行效率高,程序受影响较小日志

    缺点:没法检测出循环引用的状况,致使内存泄漏memory leak对象

可达性分析算法blog

  • 经过判断对象的引用链是否可达来决定对象是否能够被回收

能够做为GC Root的对象排序

  • 虚拟机栈中的引用对象(栈帧中的本地变量表)
  • 方法区中的常量引用对象
  • 方法区中的类静态属性引用的对象
  • 本地方法栈中JNI(Native方法)的引用对象
  • 活跃线程的引用对象

问:谈谈你了解的垃圾回收算法?生命周期

标记-清除算法(mark and sweep)内存

  • 标记:从根集合进行扫描,对存活的对象进行标记
  • 清楚:对堆内存从头至尾进行线性遍历,回收不可达对象内存,并把原来标记为可达的标记清除掉

优势:效率高,由于不须要对对象的移动操做。

缺点:碎片化,标记清除以后会留下大量不连续的内存空间,碎片太多可能会致使之后程序运行过程当中没法提供连续内存,而不得不进行另外一次垃圾回收

 

复制算法(Copying)

  • 分为对象面和空闲面
  • 对象在对象面上建立
  • 存活的对象从对象面复制到空闲面
  • 将对象面全部对象内存清除

优势:

  • 解决了碎片化的问题 (每次复制到空闲面的对象都是连续排放的)
  • 顺序分配内存,简单高效 (每次直接清理一半的内存空间,因此简单高效)
  • 适用于对象存活率低的场景,好比年轻代(如今成熟的商业虚拟机中都采用这种算法回收年轻代,由于年轻代通常只有10%的对象存活,因此使用这种算法效率还不错)

缺点:在应对对象存活率较高时就有些力不从心了,由于有较多的复制操做,效率将会变低。并且不想浪费额外的50%空间,就须要更多的空间进行担保,由于须要应对全部对象都100%存活的极端状况,因此老年代通常不能选用这种算法。

 

标记-整理算法(Compacting)

  • 标记:从根集合进行扫描,对存活的对象进行标记
  • 清除:移动全部存活的对象,且按照内存地址次序一次排序,而后将末端内存地址之后的内存所有回收

优势:解决了内存碎片化的问题,清理以后内存是连续的,也不用设置两块内存互换,适用于存活率较高的场景

缺点:须要移动标记存活的对象,成本较高

分代收集算法(Generational Collector) 如今主流的GC算法

  • 垃圾回收算法的组合拳
  • 按照对象生命周期的不一样划分区域以采用不一样的垃圾回收算法
  • 目的:提升JVM的回收效率

JDK8以后没有永久代,可是年轻代、老年代都保留了下来,年轻代使用的是复制算法,老年代使用的标记整理算法

问:分代收集算法的GC分几种?

  • Minor GC (发生在年轻代中的垃圾收集工做,使用复制算法。年轻代是全部java对象出生的地方,新对象通常存活率较低,因此MinorGC比较频繁)
  • Full GC 

年轻代:

  • Eden区(就是伊甸园,表明这人类的起源,新对象存放的区域,若是eden区放不下新对象,也有可能会放在survivor区甚至是老年代中)
  • 两个Survivor区(幸存者区,from区和to区,这两个区也不是固定的,会随着垃圾回收而相互转换)

默认是8:1:1的比例分配,垃圾清理时会将eden和from区的存活对象一次性复制到to区,to区不够用的时候须要老年代作担保

年轻代垃圾回收的过程演示:

每次存活就会标记+1,默认是15岁,也能够设置-XX:MaxTenuringThreshold设置最大年龄限制,到达限制就会进入老年代,固然若是eden或者survivor装不下也会进入老年代

对象如何晋升为老年代:

  • 经历必定Minor次数依然存活的对象
  • Survivor区放不下的对象
  • 新生成的大对象(能够设置-XX:+PretenuerSizeThreshold设置大对象大小,超过这个大小的大对象会直接放入老年代)

经常使用的调优参数:

  • -XX:SurvivorRatio:Eden和Survivor的比值,默认8:1
  • -XX:NewRatio:老年代和年轻代内存大小比例,好比2表示老年代是年轻代的2倍

老年代:存放生命周期较长的对象

  • 标记-清理算法
  • 标记-整理算法

通常会伴随着新生代的回收及整个堆的回收(FullGC和MajorGC,FullGC比MinorGC慢,但执行频率低)

问:出发FullGC的条件?

  1. 老年代空间不足(最好不要建立太大对象)
  2. 永久代空间不足(JDK7之前的版本,这也是JDK8使用元空间替代永久代的缘由,下降了FullGC的频率)
  3. CMS GC时出现promotion failed ,concurrent mode failure(注意日志里是否出现这两个状况,这两种状况很容易触发FullGC)
  4. Minor GC 晋升到老年代的平均大小大于老年代剩余空间(hotspot在进行MinorGC作了个统计,若是晋升到老年代的平均大小大于老年代剩余空间就直接触发Full GC)
  5. 调用System.gc()(这只是程序提醒虚拟机,码农但愿这里进行一下回收,但回不回收仍是要看JVM)
  6. 使用RMI来进行RPC或者管理JDK应用,默认每小时执行一次FullGC
相关文章
相关标签/搜索