24 垃圾回收

如何判断对象是否死亡

  • 引用计数法

    • 每当一个地方引用它,就加一。引用失效,就减一。
    • 缺点:无法避免循环引用。
  • 可达性分析算法

    • 对象与GCroot没有任何路径相连证明对象不可用。
    • 可作为gc root的对象包括下面几种

      • 虚拟机栈中引用的对象
      • 本地方法栈中引用的对象
      • 方法区中类静态属性引用的对象
      • 方法区中常量引用的对象
      • 所有被同步锁持有的对象?

简单的介绍一下强引用、软引用、弱引用、虚引用(虚引用与软引用和弱引用的区别、使用软引用能带来的好处)

  • 强引用

    • 宁可out of memory,gc也不会回收它。
  • 软引用

    • 内存足够就不回收,内存不够就回收。可用来实现内存敏感的高速缓存。
  • 弱引用

    • 不管内存够不够,发现了就回收。
  • 虚引用

    • 和没有引用一样,任何时候都可能被回收,主要用来跟踪对象被垃圾回收的活动。

宣告对象死亡需要经历两次标记

  1. 不可达算法判断不可达后,第一次标记。
  2. 被标记的对象经过“是否有必要执行finalize方法”筛选
  3. 被筛选出的对象第二次标记,放在一个队列中,除非重新被引用,否则就会被真的回收。?怎么判断重新被引用?

如何判断一个常量是废弃常量

  • jdk1.7前,运行时常量池包含字符串常量池,在方法区,对应永久代。
  • jdk1.7后,字符串常量池在堆,运行时常量池还在方法区,对应永久代。
  • jdk1.8后,字符串常量池还在堆,运行时常量池在方法区,对应元空间。
  • 当没有任何对象引用常量,就说明常量可回收了。

如何判断一个类是无用的类

  • 所有实例都已经被回收,堆中没有该类的实例。
  • 加载该类的classLoader已经被回收
  • 该类对应的java.lang.class对象没有在任何地方被引用,无法在任何地方通过反射访问该类的方法。

垃圾收集算法

  1. 标记-清除算法

    • 标出来的留着。剩下的回收。
    • 效率不高,会导致内存空间不连续。
  2. 标记-复制算法

    • 一半一半的使用内存空间,把左边存活的都挪到右边,然后把左边清空。
  3. 标记-整理算法

    • 把留下的挨个排好,剩下的内存区域清空。针对老年代。
  4. 分代收集算法

    • 分成新生代老生代选择不同算法。

HotSpot 为什么要分为新生代和老年代?
针对不同代的特点选择不同的回收算法。

垃圾回收器

  1. serial

    • 仅使用一个线程去收集。
    • 收集的时候暂停其他所有工作线程。
    • 新生代标记复制,老年代标记整理。
    • 没有线程交互的开销,简单高效。
  2. parnew

    • 多线程版本的serial。
    • 收集的时候暂停其他所有工作线程。
    • 新生代标记复制,老年代标记整理。
  3. parallel scanvage

    • 和parnew几乎一样
    • 关注吞吐量:cpu中用于运行用户代码时间与总消耗时间的比值。
  4. serial old
  5. parallel old
  6. cms

    • concurrent mark sweep 追求最短停顿时间,基本实现垃圾收集线程和用户线程同时工作。
    • 标记-清除

      • 初始标记:极短。暂停所有线程,标记可达对象对象。
      • 并发标记:长。开启用户线程,记录可达对象和用户线程这段时间发生的引用更新。
      • 重新标记:短。暂停所有线程。处理并发标记期间的引用更新。
      • 并发清除:开启用户线程,清扫未标记的区域。?并发清除阶段发生的引用更新怎么办
  7. g1收集器

    • 针对多核大内存机器,停顿低吞吐高。
    • 充分利用多核,和用户线程并行。
    • 分代
    • 整体看标记整理,部分看标记复制。
    • 停顿时间可预测
    • 维护优先列表,根据收集时间,优先选择回收价值最大的region回收。名字garbage first的由来。
  8. zgc收集器

    • 标记-复制算法,停顿时间更少。
      24 垃圾回收_第1张图片

    分配担保机制?

分区与GC
在jdk7前,堆内存被分为新生代、老生代、永久代三个区域。
jdk8之后永久代被彻底移除了,取而代之的是元空间。

新生代分为eden区,s0(from),s1(to)区。分配比例是8:1:1,可通过参数动态调整。
对象首先在eden区分配(如果太大就直接在老年代分配)。
当新生代空间不够时,发起minorGC。
在一次新生代垃圾回收后,如果对象还存活,年龄+1并进入survivor区,当年龄达到阈值(有的默认15,为什么是15,因为记录年龄的字段只有4位,CMS默认6)会进入老生代。
经过一次minorGC后,eden区和from区已经被清空,to区可能有对象存活,然后交换from和to。等to区被填满,所有对象移动到老生代中。

动态年龄计算:hotspot遍历所有对象,按照年龄大小对其所占用的大小进行累计,累计到survivor区的一半时,取这个年龄MaxTenuringThreshold中更小的值作为新的晋升年龄。

fullGC:当统计数据说youngGC之前晋升的平均大小比目前oldGen剩余空间大,则会触发FullGC,收集整个java堆和方法区。

你可能感兴趣的:(java)