垃圾回收

垃圾回收

在垃圾回收中,我们需要判断三个条件,什么时候回收?在哪里回收?以及如何回收

1:hotspot的GC分类

  • partial GC,并不收集整个GC堆的模式
    • young GC,只收集年轻代的GC
    • old GC,只收集老年代的GC,只有CMS中的concurrent collection是这个模式
    • mixed GC,收集整个年轻代以及部分老年代的GC,只有G1是这个模式
  • full GC,收集整个堆
    • 包括young,old,永久代(如果存在的话)
  • major GC,通常和full GC 是等价的,收集整个GC堆,有人说 major GC的时候,一定要问一下是上面的ull GC,还是 old GC

2:判断对象死亡

  • 引用计数法
    • 给一个对象加上一个引用计数器,每次引用数字加一,引用失效数字减一
    • 计数器为0 的时候,对象不可能被使用
      • 循环依赖的问题
    • 引用的类型
      • 强引用
        • 生活中的必备品
        • 只有强引用是包内可见的,其他的都是public
        • 普通创建的对象默认都是强引用的,在JVM中,即使抛出OOM,强引用也不会被回收
      • 弱引用
        • 可有可无的商品
        • 内存敏感的高速缓存
        • 在内存不够的时候,他会为了避免抛出OOM,而回收掉弱引用
      • 软引用
        • 在任何时间都可能会被清除掉
        • 只要一旦被 GC看到,就会被清除
      • 虚引用
        • 形同虚设
        • 跟踪对象被垃圾回收的活动
  • 可达性质分析
    • 从GCroots开始,从该点开始向下搜索,走过的称为引用链。如果一个对象没有在引用恋上,说明是不可达的
      • 虚拟机栈中的引用的对象
      • 本地方法栈(native)中引用的对象
      • 本地区中类静态属性引用的对象
      • 本地区中常量引用的对象
      • 所有被同步锁持有的对象
    • 不可达的并非非死不可
      • 不可达的对象,可以看作是死缓
      • 此对象是否有必要执行inalize方法,
        • 当对象没有覆盖finalize的时候
        • finalize 已经被虚拟机调用的时候
      • finalize方法
        • finalize 是object的方法,当垃圾回收回收掉对象之前,就会调用这个的方法,处理最后的后事
          • 如果它覆盖了finalize方法,并且在调用的时候,引用到了GC roots链上,此时就活了
        • finalize 只能调用一次

3:常量是废弃常量?

  • 运行时常量池主要存放的是常量,那么,我们如何判断一个常量是不是废弃常量呢?
    • JDK 1.7之前,常量池放在方法区,因此对方法区的实现是永久代
    • JDK1.7,字符串常量池被拿到了堆中,而其他的常量池还在方法区,也就是永久代
    • 1.8,移除了永久代用元空间来取而代之,运行时的字符串常量池还在堆中,运行时常量池还在方法区,只不过方法区由永久代变成了元空间
  • 假设字符串常量池中有“”abc“,如果当前没有任何的string对象引用该对象的话,那么说明就是废弃对象。

4:类是一个无用的类?

  • 该类的所有实例已经回收,即在堆中不存在任何的类对象
  • 加载该类的classLoader已经被回收
  • 该类的java.lang.Class没有在任何对象引用过,无法在任何对方通过反射访问该类的方法
    • 在满足上面三个条件之后,JVM可以对该类进行回收,但是也并不绝对

5:垃圾回收算法

  • 标记清除
    • 标记出所有不需要回收的对象
    • 清除掉所有没有标记的对象
      • 简单
      • 存在内碎片
  • 标记整理
    • 标记出所有不需要回收的算法
    • 让存活者的进行移动,使得不存在内存碎片
    • 清除掉剩余的空间即可
  • 复制
    • 内存分为两块
    • 每次使用其中的一块,当这一块使用完之后,就将活着的对象复制到另外一边去
    • 再把这边的对象整体清除掉
      • 效率高
      • 浪费空间
  • 分代回收
    • 根据对象的年龄,来综合的使用上述各种垃圾回收方法
    • 在新生代,死亡的概率是很高的,选择复制算法,每次复制少量的对象,并且效率高
    • 在老年代,成活的效率比较高,使用标记清除,或者是标记整理的算法进行收集
    • 过程
      • 新生代和老年代,大概约为1:2
      • 新生代中又分为伊甸区,from survivor,to survivor,默认是8:1:1
      • 新生的对象都是在伊甸区,每次清除的时候会将伊甸区和 from survivor 中存活的对象移动到 to survivor中
      • 清除 伊甸区和 from survivor,再把 to survivor中的对象移动到from survivor
      • 老生代当达到某个数值的时候就会出发全局的垃圾回收
    • 年龄
      • 每次from survivor 和 to survivor之间的互相移动,年龄加一
      • 当年龄达到15的时候,就移动到老年区,因为在mark word 中年龄是 4位
      • 大对象直接在老年区

6:垃圾收集器

  • serial(串行) 收集器

    • 使用一条线程进行垃圾收集工作
    • 进行垃圾回收的时候会暂停其他的线程(stop the world)
      • 优点
        • 简单,高效
        • 由于没有线程的交互开销,可以获得很高的单线程收集效率
        • 运行在client 模式下的虚拟机是一个很不错的选择
  • parnew 收集器

    • 就是串行收集器的 多线程版本,和serial一模一样
    • 新生代采用标记——复制算法,而老年代采用标记,清除算法
      • 运行在server端的首要选择
      • 只有serial,和parnew配合工作
  • parallel scavenge 收集器

    • 关注的是吞吐量,高效率的使用CPU
    • 新生代采用标记复制算法,老年代采用标记整理算法
  • CMS 收集器

    • 获取最短回收停顿时间为目标的收集器,符合在用户体验的使用
    • 第一款的并发收集器,实现了垃圾回收和用户线程同时工作
      • 初始标记:暂停所有的线程,记录下和GC roots 相连的对象
      • 并发标记:开启GC 和用户线程,用一个闭包的结构去记录可达对象
      • 重新标记:修正在并发标记阶段因为用户程序运行导致的变动标记记录
      • 并发清除:开启用户线程,同时GC线程开始对未标记的区域做清扫
    • 优点
      • 并发标记 停顿小
    • 缺点
      • 对CPU 资源敏感
      • 无法处理浮动的额垃圾
      • 标记清除,导致有大量的内存碎片
  • G1 收集器

    • 面向服务器的垃圾回收器,针对多核处理器和大内存的机器
    • 并发和并行:G1能够充分的利用CPU,多核,大内存的硬件优势
    • 分代收集:也采用了分代回收的机制
    • 空间整合:G1从整体上来看是使用标记整理,从局部上是标记复制
    • 可以预测的停顿:能偶建立可预测的停顿时间模型,
      • 过程
        • 初始标记
        • 并发标记
        • 最终标记
        • 筛选回归
      • 维护了一个优先队列,每次根据收集时间,以此选择价值最大的垃圾
      • garage First,保证了在有限的时间内能够获得最大价值的垃圾回收
  • ZGC 收集器

    • stop the world 的情况会更少

2021.3.12.12:09

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值