面试 JVM 八股文十问十答第九期
相信看了本文后,对你的面试是有一定帮助的!关注专栏后就能收到持续更新!
⭐点赞⭐收藏⭐不迷路!⭐
1)G1垃圾收集器回收流程:
G1(Garbage-First)是JDK 7引入的一种垃圾收集器,专为提供更低停顿时间和更好的堆管理而设计。其回收过程包括以下几个阶段:
- 初始标记(STW阶段):这个阶段标记直接从GC根节点可达的存活对象,是一个短暂的停顿阶段,所有应用线程都会暂停。
- 并发标记:在这个阶段,G1与应用线程并发标记存活对象。它从GC根节点开始追踪对象图,标记可达对象。
- 再标记(STW阶段):这个阶段用于处理并发标记期间发生的变化,识别并更新对象图中在标记阶段被修改的对象。
- 并发清理:G1将堆划分为多个区域,选择含有大量垃圾的区域进行清理。它并发地将存活对象从这些区域复制到幸存者区域或老年代空间。
- 清理:在清理完成后,G1清理空的区域以便未来的分配使用。
2)CMS垃圾收集器回收流程:
CMS(Concurrent Mark-Sweep)是Java中的另一种垃圾收集器,旨在通过大部分工作与应用线程并发执行来最小化垃圾收集停顿时间。其回收流程包括以下步骤:
- 初始标记(STW阶段):与G1类似,CMS从初始标记阶段开始,识别初始的存活对象。
- 并发标记:CMS并发地执行标记阶段,与应用线程同时执行。
- 并发清除:标记完成后,CMS并发执行清除阶段,识别和释放不可达对象占用的内存空间。
- 并发重置:CMS执行额外的清理任务,如并发地重置内部数据结构。
3)ZGC垃圾收集器:
ZGC是JDK 11引入的低延迟垃圾收集器,旨在将GC停顿时间控制在一定阈值内,通常低于10毫秒。它与CMS和G1相比有几个不同点:
- 基于区域:类似于G1,ZGC将堆划分为区域,以实现更有效的垃圾收集。
- 并发压缩:与G1和CMS不同,ZGC可以并发地进行压缩,允许在应用程序运行时进行堆的碎片整理。
- 彩色指针:ZGC使用彩色指针来区分指向存活对象和死亡对象的指针,从而更有效地进行对象的转移和清理。
总结来说,尽管G1、CMS和ZGC都致力于减少垃圾收集停顿时间,但它们在实现这一目标的方法和技术上有所不同。G1注重可预测性和空间管理,CMS注重降低停顿时间,而ZGC则专注于实现低延迟的并发垃圾收集。
4)CMS 写屏障又是维护卡表,又得维护增量更新?
CMS(Concurrent Mark-Sweep)垃圾收集器在执行过程中需要维护卡表和执行增量更新。
- 卡表(Card Table):卡表是一种数据结构,用于记录堆中哪些对象发生了变化。在CMS的并发标记阶段,应用线程会修改对象,这可能导致标记阶段与清理阶段之间的不一致性。为了解决这个问题,CMS使用卡表记录对象的变化,在清理阶段根据卡表信息来更新标记状态。
- 增量更新(Incremental Update):CMS在执行垃圾收集时,需要在标记阶段和清理阶段之间保持一致性。为了减小标记阶段的停顿时间,CMS采用增量更新技术。增量更新是指在应用线程运行的同时,CMS会不断地进行部分标记和清理工作,逐步完成整个垃圾收集过程。这样可以将长时间的停顿分解成多个短暂的停顿,减少对应用程序的影响。
5)GC 调优的两大目标是啥?
GC 调优的两大目标是:
- 降低垃圾收集停顿时间:垃圾收集停顿会影响应用程序的响应性和性能。通过减少垃圾收集停顿时间,可以提高应用程序的吞吐量和响应速度,提升用户体验。
- 减少内存占用:垃圾收集器的运行需要消耗系统资源,包括CPU和内存。通过减少内存占用,可以提高系统的资源利用率,降低成本,并减少因频繁垃圾收集而导致的性能问题。
6)GC 如何调优?
GC 调优包括以下几个方面:
- 选择合适的垃圾收集器:根据应用程序的特点和性能要求,选择合适的垃圾收集器。比如,对于低延迟要求高的应用,可以选择ZGC或者G1;对于内存占用要求高的应用,可以选择CMS。
- 调整堆大小:合理调整堆大小可以减少垃圾收集的频率和停顿时间。如果堆过大,可能会导致长时间的垃圾收集停顿;如果堆过小,可能会频繁触发垃圾收集,影响应用性能。
- 优化垃圾收集器参数:根据应用程序的特点和性能需求,调整垃圾收集器的参数,如年轻代和老年代的比例、GC线程数等,以达到最佳的性能表现。
- 监控和分析GC日志:通过监控和分析GC日志,可以了解垃圾收集器的运行情况,发现潜在的性能问题,并进行针对性的调优。
- 避免内存泄漏:及时发现和修复内存泄漏问题,防止不必要的内存占用,减少垃圾收集的压力。
综上所述,GC调优是一个综合性的工作,需要结合应用程序的特点和性能需求,采取多种手段来优化垃圾收集器的运行效率和性能表现。
7)常用的 JVM 配置参数有哪些?
常用的 JVM 配置参数包括:
- 堆大小参数:包括
-Xms
(初始堆大小)和-Xmx
(最大堆大小),用于指定Java堆的初始大小和最大大小。 - 新生代和老年代参数:
-Xmn
用于指定新生代的大小,-XX:NewRatio
用于指定新生代和老年代的比例。 - 永久代参数(在JDK 8之前):包括
-XX:PermSize
和-XX:MaxPermSize
,用于指定永久代的初始大小和最大大小。 - GC 相关参数:包括选择垃圾收集器的参数(如
-XX:+UseG1GC
、-XX:+UseConcMarkSweepGC
等),以及控制GC行为的参数(如-XX:+PrintGC
、-XX:+PrintGCDetails
等)。 - 线程参数:包括
-Xss
用于指定线程栈大小,-XX:ParallelGCThreads
用于指定并行GC的线程数等。
8)说说你常用的分析 JVM 的工具?
我常用的分析 JVM 的工具包括:
- VisualVM:VisualVM是一款免费的Java虚拟机监控、调试和性能分析工具,提供了丰富的功能,包括监控应用程序的内存、线程、类加载、垃圾收集等情况,并且可以通过插件扩展功能。
- JVisualVM:JVisualVM是VisualVM的一个子集,通常随JDK一起提供。它提供了基本的监控和分析功能,可以用于快速查看应用程序的性能状况。
- jstat:jstat是JDK自带的一个命令行工具,用于监控JVM内存、垃圾收集等情况,可以输出各种统计信息,如堆内存使用情况、垃圾收集统计等。
- jmap:jmap也是JDK自带的一个命令行工具,用于生成Java堆转储文件(heap dump),可以用于分析内存泄漏等问题。
9)内存泄露分析该怎么做?
内存泄漏分析通常可以通过以下步骤进行:
- 确认是否存在内存泄漏:观察应用程序的内存占用情况,检查是否有持续增长的趋势或者频繁的Full GC等现象。
- 生成Heap Dump:使用工具如jmap生成应用程序的Heap Dump文件,记录应用程序内存中的对象和其引用关系。
- 分析Heap Dump:使用Heap Dump分析工具(如Eclipse Memory Analyzer)分析Heap Dump文件,查看内存中的对象引用关系,找出可能存在内存泄漏的对象。
- 定位内存泄漏源:根据Heap Dump分析结果,定位可能引发内存泄漏的代码逻辑或对象引用,例如未及时释放资源、静态变量持有对象等。
- 修复内存泄漏:根据定位的内存泄漏源,修改代码逻辑或释放对象引用,确保内存得到正确释放。
- 验证修复效果:重新运行应用程序,观察内存占用情况,确认内存泄漏问题是否得到解决。
10)为什么新生代又要分 s1、s2 和 eden?
新生代被分为S0(Survivor 0)、S1(Survivor 1)和Eden区的主要目的是为了实现复制算法的高效垃圾回收。
- Eden区:新对象首先会被分配到Eden区,当Eden区满时触发Minor GC,存活的对象会被复制到Survivor区(通常是S0),而Eden区中未存活的对象会被回收。
- Survivor区:Survivor区用于存放经过一次Minor GC后仍然存活的对象。当一次Minor GC发生时,存活的对象会被复制到另外一个Survivor区(比如从S0复制到S1),而非存活的对象会被回收。
通过将新生代分为两个Survivor区,可以在一次Minor GC之后,将存活的对象移到另一个Survivor区,避免了老年代和新生代之间的拷贝操作。这样可以降低存活对象的拷贝成本,提高垃圾回收的效率。
开源项目地址:https://gitee.com/falle22222n-leaves/vue_-book-manage-system
前后端总计已经 1300+ Star,2W+ 访问!
⭐点赞⭐收藏⭐不迷路!⭐