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很忙时,也能采集到有用的信息。

相关推荐
缘来是庄4 分钟前
设计模式之中介者模式
java·设计模式·中介者模式
rebel33 分钟前
若依框架整合 CXF 实现 WebService 改造流程(后端)
java·后端
代码的余温2 小时前
5种高效解决Maven依赖冲突的方法
java·maven
慕y2742 小时前
Java学习第十六部分——JUnit框架
java·开发语言·学习
paishishaba2 小时前
Maven
java·maven
张人玉2 小时前
C# 常量与变量
java·算法·c#
Java技术小馆3 小时前
GitDiagram如何让你的GitHub项目可视化
java·后端·面试
Codebee3 小时前
“自举开发“范式:OneCode如何用低代码重构自身工具链
java·人工智能·架构
掘金-我是哪吒3 小时前
分布式微服务系统架构第158集:JavaPlus技术文档平台日更-JVM基础知识
jvm·分布式·微服务·架构·系统架构
程序无bug3 小时前
手写Spring框架
java·后端