请你谈谈System.gc()&&STW&&垃圾回收的并发与并行&&安全点与安全区域的理解

1为什么需要System.gc()

1、除了堆内存以外,其他的内存,有些也是需要 GC 的。例如:MetaSpace,CodeCache,Direct Buffer,MMap Buffer 等等。早期在 Java 8 之前的 JVM,对于这些内存回收的机制并不完善,很多情况下都需要 FullGC 扫描整个堆才能确定这些区域中哪些内存可以回收。

2、对于 WeakReference,无论是 Young GC 还是 FullGC 就会被回收;SoftReference 只有在 FullGC 的时候才会被回收。当我们程序想主动对于这些引用进行回收的时候,需要能触发 GC 的方法,这就用到了System.gc()。

2System.gc() 背后的原理

System.gc()实际上调用的是RunTime.getRunTime().gc():

public static void gc() {
    Runtime.getRuntime().gc();
    //这个方法是一个 native 方法:public native void gc();
}

JVM源码:

JVM_ENTRY_NO_ENV(void, JVM_GC(void))
  JVMWrapper("JVM_GC");
  //如果没有将JVM启动参数 DisableExplicitGC 设置为 false,则执行 GC,GC 原因是 System.gc 触发,对应 GCCause::_java_lang_system_gc
  if (!DisableExplicitGC) {
    Universe::heap()->collect(GCCause::_java_lang_system_gc);
  }
JVM_END

首先,根据 DisableExplicitGC JVM 启动参数的状态:确定是否会 GC,如果需要 GC,不同 GC 会有不同的处理。

G1 GC 的处理

如果是 System.gc() 触发的 GC,G1 GC 会根据 ExplicitGCInvokesConcurrent 这个 JVM 参数决定是默认 GC (轻量 GC,YoungGC)还是 FullGC。

ZGC 的处理

直接不处理,不支持通过 System.gc() 触发 GC。

Shenandoah(沈南多啊) GC 的处理

Shenandoah 的处理和 G1 GC 的类似:先判断是不是用户明确触发的 GC,然后通过 DisableExplicitGC JVM 参数判断是否可以 GC:如果可以,则请求 GC,阻塞等待 GC 请求被处理。然后根据 ExplicitGCInvokesConcurrent 这个 JVM 参数决定是默认 GC (轻量并行 GC,YoungGC)还是 FullGC。

其中,DisableExplicitGC && ExplicitGCInvokesConcurrent

DisableExplicitGC:是否禁用显式 GC,默认是不禁用的。
ExplicitGCInvokesConcurrent:对于显式 GC,是执行轻量并行 GC (YoungGC)还是 FullGC,如果为 true 则是执行轻量并行 GC (YoungGC),false 则是执行 FullGC。

3STW(Stop The World)

可达性分析算法中枚举根节点(GC ROOTS)会导致所有java执行线程停顿,分析工作必须在一个能确保一致性的快照中进行。所有的GC都会有STW。G1也不能完全的避免STW,尽可能的缩短暂停时间。

4垃圾回收的并行与并发

并行:多条垃圾回收线程并行工作,但此时用户线程仍处于等待状态【ParNew 、Parallel Scavenge 、Parallel Old】
串行:单线程执行。
在这里插入图片描述
并发(Concurrent):用户线程与垃圾回收线程同时执行(但不一定是并行的,可能会发生交替执行),垃圾回收线程在执行时不会停顿用户程序的运行;用户程序继续运行,而垃圾回收程序运行在另一个CPU上【CMS、G1】

在这里插入图片描述

5安全点与安全区域

程序运行时,并非在所有的地方都能停顿下来开始GC,只有在特定的位置才能停顿下来GC,这个位置称之为“安全点”。如何在GC发生时,检查所有线程都跑到最近的安全点停顿下来? 主动式中断:设置一个中断标志,各个线程运行到Safe point的时候主动轮询这个标志,如果中断为真,则将自己进行中断挂起。
但是安全点机制保证了程序执行时,在不长的时间内就会遇到可进入GC的safePoint 。但是在程序 sleep blocked状态,这时候线程就无法响应JVM中断请求,我们就需要使用安全区域去解决这个问题。安全区域指:在一段代码中,对象的引用关系不会发生变化,在这个区域中的任何位置开始GC都是安全的。实际执行时:当线程运行到Safe Region的代码时,首先标识已经进入了safe Region,如果这段时间内发生了GC,JVM会忽略标识为safe Region 状态的线程,当线程即将离开safe Region时 会检查JVM时候已经完成了GC 如果完成了就继续运行,否则,则需要等待直到可以安全离开safe region的信号为止。

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值