JVM-垃圾回收

1.如何判断对象可以回收

1.1.引用计数法

定义:给对象添加一个引用计数器,每当有一个地方引用它,计数器值就加一;相反的,当引用失效的时候,计数器值就减一;任何时刻计数器为0的对象就是不可能再被使用的。
弊端:可能存在无效的循环引用

现在主流的Java虚拟机里并没有选用引用计数算法来管理内存,最主要的原因就是它很难解决对象之间相互循环引用的问题

1.2.可达性分析算法

  • Java虚拟机中的垃圾回收器采用可达性分析来探索所有存活的对象
  • 扫描堆中的对象,看是否能够沿着GC Root对象为起点的引用链找到该对象,找不到,表示可以回收
  • 哪些对象可以作为GC Root?
    • 虚拟机栈(栈帧中的本地变量表)中引用的对象。
    • 方法区中类静态属性引用的对象。
    • 方法区中常量引用的对象。
    • 本地方法栈中JNI(即一般说的Native方法)引用的对象。

1.3.四种引用

  1. 强引用
  • 只有所有GX Roots对象都不通过【强引用】引用该对象,该对象才能被垃圾回收
  1. 软引用(SoftReference)
  • 仅有软引用引用该对象时,在垃圾回收后,内存仍不足时会再次触发垃圾回收,回收软引用对象
  • 可以配合引用队列来释放软引用自身
  1. 弱引用(WeakReference)
  • 仅有弱引用引用该对象时,在垃圾回收时,无论内存是否充足,都会回收弱引用对象
  • 可以配合引用队列来释放弱引用自身
  1. 虚引用(PhantomReference)
  • 必须配合引用队列使用,主要配合ByteBuffer使用,被引用对象回收时,会将虚引用入队,由Reference Handler线程调用虚引用相关方法释放直接内存
  1. 终结器引用(FinalReference)
  • 无需手动编码,但其内部配合引用队列使用,在垃圾回收时,终结器引用入队(被引用对象暂时没有被回收),再由Finalizer线程通过终结器引用找到被引用对象并调用它的finalize方法,第二次GC时才能回收被引用对象

2.垃圾回收算法

2.1.标记清除

定义:Mark Sweep

  • 速度较快
  • 会造成内存碎片

2.2.标记整理

定义:Mark Compact

  • 速度慢
  • 没有内存碎片

2.3.复制

定义:Copy

  • 不会有内存碎片
  • 需要占用双倍内存空间

3.分代垃圾回收

  • 对象首先分配在伊甸园区域
  • 新生代空间不足时,触发minor gc,伊甸园和from存活的对象使用copy复制到to中,存活的对象年龄加1并且交换from to
  • minor gc会引发stop the world,暂停其它用户的线程,等来及回收结束后,用户线程才恢复运行
  • 当对象寿命超过阈值,会晋升至老年代,最大寿命是15(4bit)
  • 当老年代空间不足,会先尝试触发minor gc,如果之后空间仍不足,那么触发full gc,STW的时间更长

3.1相关JVM参数

4.垃圾回收器

  1. 串行
  • 单线程
  • 堆内存较小,适合个人电脑
  1. 吞吐量优先
  • 多线程
  • 堆内存较大,多核cpu
  • 让单位时间内STW的时间最短
  1. 响应时间优先
  • 多线程
  • 堆内存较大,多核cpu
  • 尽可能让单次STW的时间最短

4.1.串行

4.2.吞吐量优先

4.3.响应时间优先

4.4.G1

定义:Garbage First
适用场景

  • 同时注重吞吐量(Throughput)和低延迟(Low latency),默认的暂停目标是200ms
  • 超大堆内存,会将堆划分为多个大小相等的Region
  • 整体上是标记+整理算法,两个区域之间是复制算法

相关JVM参数
-XX:+UseG1GC
-XX:G1HeapRegionSize=size
-XX:MaxGCPauseMillis=time

  1. G1垃圾回收阶段

  2. Young Collection

  • 会STW
  1. Young Collection + CM
  • 在Young GC时会进行GC Root的初始标记
  • 老年代占用堆空间比例达到阈值时,进行并发标记(不会STW),由下面的参数决定
    -XX:InitiatingHeapOccupancyPercent=percent(默认45%)
  1. Mixed Collection
    会对E、S、O进行全面垃圾回收
  • 最终标记(Remark)会STW
  • 拷贝存活(Evacuation)会STW

-XX:MaxGCPauseMillis=ms

  1. Full GC
  • SerialGC
    • 新生代内存不足发生的垃圾收集-minor gc
    • 老年代内存不足发生的垃圾收集-full gc
  • ParallelGC
    • 新生代内存不足发生的垃圾收集-minor gc
    • 老年代内存不足发生的垃圾收集-full gc
  • CMS
    • 新生代内存不足发生的垃圾收集-minor gc
    • 老年代内存不足
  • G1
    • 新生代内存不足发生的垃圾收集-minor gc
    • 老年代内存不足(垃圾回收速度低于产生速度时,并发失败,退化为单线程SerialGC串行执行)
  1. Young Collection跨代引用
  • 新生代回收的跨代引用(老年代引用新生代)问题

  • 卡表与Remembered Set

  • 在引用变更时通过post -write barrier + dirty card queue

  • concurrent refinement threads更新Remembered Set

  1. Remark
  • pre-write barrier + satb_mark_queue
  1. JDK 8u20字符串去重
  • 优点:节省大量内存
  • 缺点:略微多占用了cpu时间,新生代回收时间略微增加

-XX:+UseStringDeduplication

  • 将所有新分配的字符串放入一个队列
  • 当新生代回收时,G1并发检查是否有字符串去重
  • 如果它们的值一样,让它们医用同一个char[]
  • 注意,与String.intern()不一样
    • String.intern()关注的是字符串对象
    • 而字符串去重关注的是char[]
    • 在JVM内部,使用了不同的字符串表
posted @ 2023-06-01 09:44  不修电脑  阅读(37)  评论(0编辑  收藏  举报