• JVM面试重点-2


    16. 吞吐量优先和响应时间优先的回收器是哪些?

    • 吞吐量优先:Parallel Scavenge + Parallel Old(多线程并行)->简称: PS+PO -> JDK1.8默认
    • 响应时间优先:ParNew + CMS(并发回收垃圾)

    17. GC一定会导致停顿吗,为什么一定要停顿?

    GC进行时必须暂停所有Java执行线程,称为Stop The World。

    原因:可达性分析过程中不允许对象的引用关系还在变化,否则无法保证可达性分析的准确性。GC只会在“安全点”和“安全区”内开始。

    18. Full GC后老年代的空间反而变小?

    HotSpot虚拟机的Full GC实现中,默认新生代里所有活的对象都要晋升到老年代,实在晋升不了才会留在新生代。如果Full GC的时候,老年代里的对象几乎没有死掉的,而新生代又要晋升活对象上来,那么Full GC结束后老年代的使用量自然就上升了。

    19. 发生Young GC的时候需要扫描老年代的对象吗?

    不扫描老年代。

    在分代收集中,新生代的规模一般都比老年代要小许多,新生代的收集也比老年代要频繁许多,如果回收新生代时也不得不同时扫描老年代的话,那么Young GC的效率可能下降不少。显然是不可能区扫描老年代的。

    大多数垃圾收集器(G1不同),通过CardTable来维护老年代对年轻代的引用,CardTable中标记每个Card的状态,它用BitMap来实现。 如果一个OLD区CardTable中有对象指向Y区,就将它设为Dirty,下次扫描时,只需要扫描DirtyCard。

    20. HotSpot虚拟机为什么要分为新生代和老年代?

    HotSpot根据对象存活周期将内存分块,它把Java堆分为新生代(Eden)和老年代(Survivor),然后根据各个年代的特点采用合适的收集算法。在新生代中,每次GC时都有大批对象死去,只有少量存活,所以选用复制算法(只需要付出少量存活对象的复制成本就可以完成收集)。在老年代中,对象存活率高、没有额外空间对它进行分配担保,所以使用“标记-清理”或“标记-整理”算法来回收。

    21. HotSpot虚拟机GC的分类(准确分为两大种):

    Partial GC(分代式收集):并不收集整个GC堆的模式

    • Young GC:只收集young gen的GC
    • Old GC:只收集old gen的GC。只有CMS的concurrent collection是这个模式
    • Mixed【每克死特】 GC:收集整个young gen以及部分old gen的GC。->只有G1有这个模式

    Full GC(全部收集):收集整个堆,包括young gen、old gen、perm gen(如果存在的话)等所有部分的模式。

    22. HotSpot 虚拟机GC的触发条件:

    Young GC:

    Eden区分配满的时候触发,Young GC时,有部分存活对象会晋升到old gen,所以young GC后old gen的占用量通常会有所升高。

    Full GC之前会进行一次Young GC。

    ---- ----

    CMS 垃圾回收器:配置-XX:+CMSScavengeBeforeRemark,在CMS GC前启动一次young gc,目的在 于减少old gen对ygc gen的引用,降低remark时的开销。

    Full GC:

    • 老年代没有足够的空间时,发生Full GC
    • 准备要触发Young GC时,统计要晋升old gen的对象大于目前old gen剩余的空间时,则不会触发Young GC,而是触发Full GC(除了CMS收集器之外,Full GC至少伴随一次Young GC);
    • 如果有永久代的话,在永久代需要分配空间但已经没有足够空间时,也要触发一次Full GC(JDK1.8后,没有永久代);
    • System.gc()默认触发Full GC;
    • heap dump(堆转储文件,是一个Java进程在某个时间点上的内存快照)带GC默认触发Full GC;
    • CMS GC时出现Concurrent Mode Failure会导致一次Full GC的产生。

    23. 安全点与安全区:

    OopMap:

    • 概念:记录了栈上本地变量到堆上对象的引用关系。
    • 作用:避免全栈扫描,加快枚举根节点的速度;实现HotSpot JVM的准确式GC。

    安全点:

    • 概念:JVM在一些特定的位置记录OopMap信息,这些位置称为“安全点”,运行的程序(获得CUP时间的线程)只有在“安全点”才能GC。
    • 如何让所有线程“跑”到“安全点”?
      • 抢先式中断:不需要线程的执行代码主动配合,GC发生时,中断所有线程,如果发现有线程不再“安全点”上,就恢复线程,让它“跑”到“安全点”上(几乎不用这种方案)。
      • 主动式中断:设置一个标志,每个线程主动轮询这个标志,发现中断标志为真就挂起自己。轮询标志的地方:它与“安全点”重合,然后再加上创建对象分配内存的地方(HotSpot JVM使用)。

    安全区:

    • 概念:在一段代码片段中,引用关系不会发生变化,在该区域GC都是安全的,它可以理解成是“安全点”的拓展。
    • 作用:解决没有得到CPU分配时间的线程,无法响应JVM的中断请求,“跑”到“安全点”去挂起的问题。
    • 使用:当用户线程执行到“安全区”里面的代码时,首先标识自己进入了“安全区”,在这段时间里发起GC,就不用管标识自己为“安全区”的线程,在线程离开安全区域时,会检查是否正在执行GC,如果执行GC就等完成后再离开安全区域。

    24. Happens-Before规则?(@&@)

    作用:

    先行发生原则是判断数据是否存在竞争、线程是否安全的主要依据。

    口诀:

    如果两个操作之间具有happen-before关系,那么前一个操作的结果就会对后面的一个操作可见。是Java内存模型中定义的两个操作之间的偏序关系。

    常见规则:

    • 程序顺序规则:
      • 一个线程内,按照程序代码顺序,书写在前面的操作先行发生与书写在后面的操作。
    • 锁规则:
      • 一个unlock操作"先行发生"与后面对同一个锁的lock操作,这里必须指同一个锁,后面指的是时间上的先后顺序。目的是先解锁对其他线程可见。
    • 传递性:
      • 如果A happen-before B,且B happen-before C,那么A happen - before C。
    • volatile变量规则:
      • 对一个volatile变量的写操作"先行发生"于后面对这个变量的读操作,这里的后面同样指时间上的先后顺序。
    • 线程启动规则:
      • Thread对象的start()"先行发生"于此线程的每一个动作。
    • 线程终止规则:
      • 线程中的所有操作都"先行发生"于对此线程的终止检测,我们可以通过thread.join方法结束,thread.isAlive的返回值等手段检测到线程已经终止执行。
    • 线程中断规则:
      • 对线程interrupt方法的调用"先行发生"于被中断线程的代码监测到中断时间的发生,可以通过interrupt方法检测到是否又中断发生

    25. 内存屏障的汇编指令是啥?

    内存屏障概念:

    它是一个CPU的指令,可以保证一些特定操作的执行顺序和影响一些数据的可见性。

    硬件内存屏障 X86的指令:

    • sfence(写串行化):在sfence指令前的写操作当必须在sfence指令后的写操作前完成。
    • lfence(读串行化):在lfence指令前的读操作当必须在lfence指令后的读操作前完成。
    • mfence(读写串行化):在mfence指令前的读写操作当必须在mfence指令后的读写操作前完成。
    • 原子指令:
      • 如x86上的”lock …” 指令是一个Full Barrier,执行时会锁住内存子系统来确保执行顺序,甚至跨多个CPU。
      • Software Locks通常使用了内存屏障或原子指令来实现变量可见性和保持程序顺序。

    JVM级别如何规范(JSR133):

    • LoadLoad屏障:
      • 对于(这样的语句)Load1; LoadLoad; Load2,在Load2及后续读取操作要读取的数据被访问前,保证Load1要读取的数据被读取完毕。
    • StoreStore屏障:
      • 对于Store1; StoreStore; Store2,在Store2及后续写入操作执行前,保证Store1的写入操作对其它处理器可见。
    • LoadStore屏障:
      • 对于Load1; LoadStore; Store2,在Store2及后续写入操作被刷出前,保证Load1要读取的数据被读取完毕。
    • StoreLoad屏障:
      • 对于Store1; StoreLoad; Load2,在Load2及后续所有读取操作执行前,保证Store1的写入对所有处理器可见。

    26. new一个对象的流程:***

    • 首先判断类是否被加载过:JVM收到new指令后,先去静态常量池,寻找这个类的符号引用(全限定名),检查符号引用代表的类是是否已经被加载、解析和初始化过。如果不存在,先执行类加载过程。
    • 根据类信息,先给对象分配内存(包括本类和父类的所有实例变量,不包括上面的静态变量),并设置默认值。
    • 执行初始化代码实例化,先初始化父类再初始化子类,赋予给定值。
    • 如果存在引用对象,还需要将栈对象指向到堆内存中的实际对象。

    27. jvm监控系统是通过jmx做的么?(先pass)

    JMX:

    JMX(Java Management Extensions,即Java管理扩展)在Java编程语言中定义了应用程序以及网络管理和监控的体系结构、设计模式、应用程序接口以及服务。通常使用JMX来监控系统的运行状态或管理系统的某些方面,比如清空缓存、重新加载配置文件等。

    解答:

    一般都是,要是记录比较详细的性能定位指标,都会导致进入safepoint(安全点),从而降低了线上应用性能。

    例如 jstack,jmap打印堆栈,打印内存使用情况,都会让jvm进入safepoint,才能获取线程稳定状态从而采集信息。

    同时,JMX暴露向外的接口采集信息,例如使用jvisualvm,还会涉及rpc和网络消耗,以及JVM忙时,无法采集到信息从而有指标断点。这些都是基于 JMX 的外部监控很难解决的问题。所以,推荐使用JVM内部采集 JFR,这样即使在JVM很忙时,也能采集到有用的信息。

  • 相关阅读:
    【AI大模型】基于ChatGLM-6b从零开始本地部署语言模型,步骤详细无坑版
    马斯克调整了Twitter API服务方案
    IDA的各个视图的含义,View-A、Hex View-1等
    SwiftUI 教程之 用iPad 创建真正的iOS 应用程序介绍篇
    setup获取props和自定义事件、通过expose暴露给ref获取属性和方法、setup顶层async、setup返回函数
    JdbcTemplate对象
    基于spark进行数据分析的心力衰竭可视化大屏项目
    android翻转效果时钟
    【Mybatis源码】XMLConfigBuilder构建器 - 加载XML与创建Configuration对象的过程
    高复用性自动化脚本设计实践
  • 原文地址:https://blog.csdn.net/huantai3334/article/details/139445426