jvm2-垃圾回收

垃圾回收

如何判定对象为垃圾对象

  • 引用计数法
    在对象中添加一个引用计数器,当有地方引用这个对象的时候,引用计数器+1,当引用失效时,引用计数器-1。引用计数器为零时认为失效
    这种方法解决不了相互引用的情况 虚拟机一般不用
  • 可达性分析法
    定义GCRoot(根节点),从GCRoot往下寻找,对象与gcroot没有引用链的认为可回收

可作为GCRoots的对象

  • 虚拟机栈
  • 方法区的类属性所引用的对象
  • 方法区中常量所引用的对象
  • 本地方法栈中引用的对象

打印gc信息jvm参数:
-verbose:gc -XX:+PrintGCDetails

如何回收

  • 回收策略
    • 标记-清除算法
      标记判断为垃圾的对象为可回收状态,然后清除。
      存在的问题:效率问题;空间问题(因为内存很分散造成)
    • 复制算法
    • 标记-整理算法
    • 分代收集算法
复制算法
    • 新生代
      • Eden 伊甸园
      • Survivor 存活区
      • Tenured Gen
    • 老年代
      复制算法问题:内存利用率问题
      为了解决这个问题,将内存分区

将Eden区中幸存的对象复制到Survivor中,然后清除整个Eden
一般认为能存活的对象占10%左右,当survivor中存不下时,就将对象移交老年代,由老年代做内存担保

标记-整理算法

对于老年代,可回收内存很小,复制算法回收效率不高
将需要回收的内存往一边移动,不需要回收的内存往另一边移动,然后将回收部分清除

分代收集算法

按不同年代内存区域选择对应的收集算法

何时回收

垃圾收集器

Serial收集器

最基本,发展最悠久
单线程垃圾收集器
虽然是单线程的,还会用在桌面应用中

ParNew收集器

复制算法(新生代收集器)
多线程收集器
与serial收集器的区别就是ParNew是多线程

关注点是提高回收效率

Parallel Scavenge 收集器

复制算法(新生代收集器)
多线程收集器
关注点是达到可控制的吞吐量

吞吐量:CPU用于运行用户代码的时间与CPU消耗的总时间的比值
吞吐量=执行用户代码的时间/(执行用户代码的时间+垃圾回收所占用的时间)

相关配置:
-XX:MaxGFPauseMillis垃圾收集器最大停顿时间-毫秒
-XX:CGTImeRatio吞吐量大小 只能设置(0,100)值越大吞吐量越大,默认最大值99

CMS收集器 Concurrent Mark Sweep

使用标记清除算法
标记、清除两个步骤都是并发执行

  • 工作过程
    • 初始标记
    • 并发标记
    • 重新标记
    • 并发清理
  • 优点
    • 并发收集
    • 低停顿
  • 缺点
    • 占用大量的CPU资源
    • 无法处理浮动垃圾 (清理完后又产生的垃圾需要下一次gc时才能被清理)
    • 出现Concurrent Mode Failure (内存过小)
    • 空间碎片 (标记清除算法的问题)

G1收集器

  • jdk1.7 默认垃圾收集器Parallel Scavenge(新生代)+Parallel Old(老年代)
  • jdk1.8 默认垃圾收集器Parallel Scavenge(新生代)+Parallel Old(老年代)
  • jdk1.9 默认垃圾收集器G1

jdk默认使用的收集器是根据jdk所处的环境决定的

当jdk检测到服务器内存大于2G cpu多核就会认为是server环境,就会默认使用Parallel Scavenge收集器,如果是client环境就会默认使用Serial收集器

优势

  • 并行并发
  • 分代收集(不再严格区分新生代、老年代,内存就区分为一块块的区域 记录在RmemberSet表中)
  • 空间整合
  • 可预测的停顿

步骤

  • 初始标记
  • 并发标记
  • 最终标记
  • 筛选回收
    记录有引用的对象到RmemberSet表中,将没有引用的对象清除,这样能达到可预测的停顿

与CMS比较

原文地址:https://www.cnblogs.com/zh-ch/p/14167349.html