JVM 一些常见问题QA

2024-06-13 11:04
文章标签 java jvm 常见问题 qa

本文主要是介绍JVM 一些常见问题QA,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

GC Roots


  1. 虚拟机栈中引用的对象;

  2. 本地方法栈中JNI引用的对象;

  3. 方法区中类静态变量引用的对象;

  4. 方法区中常量引用的对象;

Full GC是Minor GC+Major GC吗?


Minor GC:回收年轻代;

Major GC:回收老年代,经常会伴随至少一次的Minor GC;

Full GC:回收整个堆,年轻代+老年代;

新生代的S区动态年龄如何计算?


Hotspot遍历所有对象时,按照年龄从小到大对其所占用的大小进行累积,当累积的某个年龄大小超过了survivor区的一半时,取这个年龄和MaxTenuringThreshold中更小的一个值,作为新的晋升年龄阈值。例如:Survivor区 = 64M,desired survivor = 32M,此时Survivor区中age<=2的对象累计大小为41M,41M大于32M,所以晋升年龄阈值被设置为2,下次Minor GC时将年龄超过2的对象被晋升到老年代。

何时发生Minor GC和Full GC?(CMS为例)


  • 何时触发Minor GC?
    • 在系统需要在新生代Eden申请内存空间不足的时候触发,JVM会判断是否要先Major GC(最理想的就是直接复制到S1完事,内部解决,根本用不到Major GC)。

  • 何时触发Major GC?

    • 没开启担保机制,Minor GC前先进行一次Major GC;(1.7及以后默认开启了担保机制,1.6及以前则需要手动配置担保机制)

    • 开启了担保机制,但平均晋升对象大小 > 老年代剩余空间;

    • 设置了-XX:CMSInitiatingOccupancyFaction参数,后台会有一个线程定时扫描,如果老年代使用空间超过比值,也会执行Major GC。

  • 何时触发Full GC?

    • CMS GC时出现promotion failed和concurrent mode failure(concurrent mode failure发生的原因一般是CMS正在进行,但是由于老年代空间不足,需要尽快回收老年代里面的不再被使用的对象,这时停止所有的线程,同时终止CMS,直接进行Serial Old GC);

    • 主动触发Full GC(执行jmap -histo:live [pid])来避免碎片问题。

JVM参数配置


  1. -XX:PretenureSizeThreshold:对象大小超过设置的值,则直接分配在old区,默认为0,全部在eden分配。 此参数只对Serial及ParNew两款收集器有效。

  2. -XX:TargetSurvivorRatio=n:设置Survivor区的目标使用率,即当survivor区GC后使用率超过这个值,就可能会使较小的年龄的对象晋升;

活跃数据的大小是指,应用程序稳定运行时长期存活对象在堆中占用的空间大小,也就是Full GC后堆中老年代占用空间的大小。可以通过GC日志中Full GC之后老年代数据大小得出,比较准确的方法是在程序稳定后,多次获取GC数据,通过取平均值的方式计算活跃数据的大小。活跃数据和各分区之间的比例关系如下:

    

Major GC要不要扫描年轻代?


  1. Serial,Parallel scavenge,Parallel old回收老年代的时候还会回收年轻代,Major GC升级为Full GC;

  2. CMS有两种模式

    1. 设置了-XX:+CMSScavengeBeforeRemark,回收老年代前会先回收年轻代;

    2. 没设置的话,会扫描年轻代,但只回收老年代;

  3. G1比较特殊,它无论处于何种模式下,都不需要扫描别的代,只需要处理一下记忆集;

Safepoint和OopMap


OopMap映射表记录哪些位置存放着对象引用,协助根节点快速完成枚举过程。

Safepoint是一些特定位置,当线程运行到这些位置时,线程中的某些状态是确定的。在safePoint可以记录OopMap信息,线程在safePoint停顿,虚拟机进行GC。 

SafePoint一般出现在以下位置:循环体的结尾、方法返回前、调用方法的call之后、抛出异常的位置。这些位置保证线程不会长时间运行而无法到达safePoint,避免其他线程都停顿等待本线程。

JVM中的VMThread会一直等待直到VMOperationQueue中有操作请求出现,比如GC请求。而VMThread要开始工作必须要等到所有的Java线程进入到safepoint。JVM维护了一个数据结构,记录了所有的线程,所以它可以快速检查所有线程的状态。当有GC请求时,所有进入到safepoint的Java线程会在一个Thread_Lock锁阻塞,直到当JVM操作完成后,VM释放Thread_Lock,阻塞的Java线程才能继续运行。

safepoint只能处理正在运行的线程,它们可以主动运行到safepoint。而一些Sleep或者被blocked的线程则靠safe region来完成。线程进入到safe region的时候先标识自己进入了safe region,等它被唤醒准备离开safe region的时候,先检查能否离开,如果GC已经完成,那么可以离开,否则就在safe region呆着。

String.intern()原理


参考:深入解析String#intern

总结:jdk7 版本对 intern 操作和常量池都做了一定的修改。主要包括2点:

  • 将String常量池 从 Perm 区移动到了 Java Heap区

  • String#intern 方法时,如果存在堆中的对象,会直接保存对象的引用,而不会重新创建对象(jdk1.6会在String常量池创建对象)

看懂这个代码,就算理解了

STW期间,新请求如何处理?

如果是RPC请求,很可能会在socket buffer上阻塞,IO读写暂停,比如刚好一个请求到来,就卡住等STW结束再进服务。

怎么排查线上GC问题 & GC优化


1,首先,在进行GC优化之前,需要确认项目的架构和代码等已经没有优化空间。不能指望一个系统架构或代码有缺陷的应用,通过GC优化来飞跃;

2,其次,可以看出虚拟机内部已有很多优化来保证应用的稳定运行,所以不要为了调优而调优,不当的调优可能适得其反; 

3,最后,GC优化是一个系统而复杂的工作,没有万能的调优策略可以满足所有的性能指标,比如可能不能同时满足低延时和高吞吐;

现象:服务抖动,成功率变低,GC耗时长。

1,看内存对象有无异常,大对象长时间存活;

jmap -histo:live PID

2,看是否cache过多,长时间存活:GC前后内存使用率对比;

3,如果GC要处理内存大也会更耗时,提前GC,提高频率降低每次清理内存;

// Old区使用了50%的时候触发GC
-XX:+UseCMSInitiatingOccupancyOnly
-XX:CMSInitiatingOccupancyFraction=50

4,增加对象在年轻代内存中驻留的时间,降低GC频率;

// 注意动态年龄问题,可能生效的不一定是配置的这个(详见CMS动态年龄)
-XX:MaxTenuringThreshold=31

5,调整年轻代比例;

如何选择各分区大小应该依赖应用程序中对象生命周期的分布情况:

如果应用存在大量的短期对象,应该选择较大的年轻代;如果存在相对较多的持久对象,老年代应该适当增大。

经典比例参考:从实际案例聊聊Java应用的GC优化 - 美团技术团队

6,CMS-Remark之前强制进行年轻代GC;

// 这两个参数强制在remark阶段之前先进行一次年轻代GC,这样需要remark的内存量就不会太多(详见CMS跨带引用)
-XX:+ScavengeBeforeFullGC(Parallel GC的参数,ParNew不用配置)
-XX:+CMSScavengeBeforeRemark

Tips:

1.CMS-remark阶段需要对堆中所有的内存对象进行处理,如果在这个阶段之前强制执行一次年轻代的GC会大量减少remark需要处理的内存数量,进而降低JVM卡顿对成功率的影响;

2.对于Java HTTP服务,JVM的卡顿时间应该小于HTTP客户端的调用超时时间,否则JVM卡顿会对成功率造成影响;

这篇关于JVM 一些常见问题QA的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1057119

相关文章

Java中Switch Case多个条件处理方法举例

《Java中SwitchCase多个条件处理方法举例》Java中switch语句用于根据变量值执行不同代码块,适用于多个条件的处理,:本文主要介绍Java中SwitchCase多个条件处理的相... 目录前言基本语法处理多个条件示例1:合并相同代码的多个case示例2:通过字符串合并多个case进阶用法使用

Java中的Lambda表达式及其应用小结

《Java中的Lambda表达式及其应用小结》Java中的Lambda表达式是一项极具创新性的特性,它使得Java代码更加简洁和高效,尤其是在集合操作和并行处理方面,:本文主要介绍Java中的La... 目录前言1. 什么是Lambda表达式?2. Lambda表达式的基本语法例子1:最简单的Lambda表

Java中Scanner的用法示例小结

《Java中Scanner的用法示例小结》有时候我们在编写代码的时候可能会使用输入和输出,那Java也有自己的输入和输出,今天我们来探究一下,对JavaScanner用法相关知识感兴趣的朋友一起看看吧... 目录前言一 输出二 输入Scanner的使用多组输入三 综合练习:猜数字游戏猜数字前言有时候我们在

Spring Security+JWT如何实现前后端分离权限控制

《SpringSecurity+JWT如何实现前后端分离权限控制》本篇将手把手教你用SpringSecurity+JWT搭建一套完整的登录认证与权限控制体系,具有很好的参考价值,希望对大家... 目录Spring Security+JWT实现前后端分离权限控制实战一、为什么要用 JWT?二、JWT 基本结构

java解析jwt中的payload的用法

《java解析jwt中的payload的用法》:本文主要介绍java解析jwt中的payload的用法,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录Java解析jwt中的payload1. 使用 jjwt 库步骤 1:添加依赖步骤 2:解析 JWT2. 使用 N

springboot项目如何开启https服务

《springboot项目如何开启https服务》:本文主要介绍springboot项目如何开启https服务方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录springboot项目开启https服务1. 生成SSL证书密钥库使用keytool生成自签名证书将

Java实现优雅日期处理的方案详解

《Java实现优雅日期处理的方案详解》在我们的日常工作中,需要经常处理各种格式,各种类似的的日期或者时间,下面我们就来看看如何使用java处理这样的日期问题吧,感兴趣的小伙伴可以跟随小编一起学习一下... 目录前言一、日期的坑1.1 日期格式化陷阱1.2 时区转换二、优雅方案的进阶之路2.1 线程安全重构2

Java中的JSONObject详解

《Java中的JSONObject详解》:本文主要介绍Java中的JSONObject详解,需要的朋友可以参考下... Java中的jsONObject详解一、引言在Java开发中,处理JSON数据是一种常见的需求。JSONObject是处理JSON对象的一个非常有用的类,它提供了一系列的API来操作J

SpringBoot多数据源配置完整指南

《SpringBoot多数据源配置完整指南》在复杂的企业应用中,经常需要连接多个数据库,SpringBoot提供了灵活的多数据源配置方式,以下是详细的实现方案,需要的朋友可以参考下... 目录一、基础多数据源配置1. 添加依赖2. 配置多个数据源3. 配置数据源Bean二、JPA多数据源配置1. 配置主数据

将Java程序打包成EXE文件的实现方式

《将Java程序打包成EXE文件的实现方式》:本文主要介绍将Java程序打包成EXE文件的实现方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录如何将Java程序编程打包成EXE文件1.准备Java程序2.生成JAR包3.选择并安装打包工具4.配置Launch4