JVM与Spring Boot解析

📕我是廖志伟,一名Java开发工程师、《Java项目实战——深入理解大型互联网企业通用技术》(基础篇)(进阶篇)、(架构篇)、《解密程序员的思维密码——沟通、演讲、思考的实践》作者、清华大学出版社签约作家、Java领域优质创作者、优快云博客专家、阿里云专家博主、51CTO专家博主、产品软文专业写手、技术文章评审老师、技术类问卷调查设计师、幕后大佬社区创始人、开源项目贡献者。

📘拥有多年一线研发和团队管理经验,研究过主流框架的底层源码(Spring、SpringBoot、SpringMVC、SpringCloud、Mybatis、Dubbo、Zookeeper),消息中间件底层架构原理(RabbitMQ、RocketMQ、Kafka)、Redis缓存、MySQL关系型数据库、 ElasticSearch全文搜索、MongoDB非关系型数据库、Apache ShardingSphere分库分表读写分离、设计模式、领域驱动DDD、Kubernetes容器编排等。

📙不定期分享高并发、高可用、高性能、微服务、分布式、海量数据、性能调优、云原生、项目管理、产品思维、技术选型、架构设计、求职面试、副业思维、个人成长等内容。

Java程序员廖志伟

💡在这个美好的时刻,笔者不再啰嗦废话,现在毫不拖延地进入文章所要讨论的主题。接下来,我将为大家呈现正文内容。

优快云

JVM知识体系概述

Java虚拟机(JVM)是Java语言的运行环境,它负责将Java字节码转换为机器码执行。JVM的设计考虑了内存管理、垃圾回收、多线程并发等多个复杂问题,以下是对JVM知识体系的详细解析。

类加载机制

类加载机制是JVM的核心功能之一,负责从文件系统或网络中加载Class文件,并将其转换成JVM能够使用的Java类型。类加载过程主要分为三个阶段:加载、连接和初始化。

  1. 加载:加载Class文件到JVM中,包括类的定义信息、静态字段、方法信息等。在这个过程中,JVM会检查类的名称是否合法,以及是否与已加载的类冲突。

  2. 连接:连接阶段包括验证、准备和解析三个子阶段。

    • 验证:确保Class文件的字节码符合JVM规范,包括类文件格式、字节码结构、访问权限等。验证过程涉及对字节码的语法、语义和运行时行为的检查。
    • 准备:为类变量分配内存,并设置默认初始值。对于基本数据类型,初始值为0;对于引用数据类型,初始值为null。
    • 解析:将符号引用转换为直接引用。符号引用是类、接口、字段和方法的名称和类型,而直接引用是直接指向对象的引用。
  3. 初始化:执行类构造器方法( ()),初始化类变量和静态变量。初始化过程包括初始化类变量、静态初始化块和父类构造器方法。

双亲委派模型

双亲委派模型是JVM中类加载器的一种工作模式,它要求除了顶层的启动类加载器外,其余的类加载器都应当有自己的父类加载器。当一个类加载器请求加载某个类时,它首先委托给父类加载器进行加载,只有当父类加载器无法完成加载任务时,才自己去尝试加载。这种模式确保了类加载的一致性和隔离性。

自定义类加载器

自定义类加载器允许开发者实现自己的类加载逻辑,例如加载特定格式的文件、实现模块化系统等。自定义类加载器需要继承java.lang.ClassLoader类,并重写findClass方法。

模块化系统(JPMS)

Java Platform Module System(JPMS)是Java 9引入的模块化系统,它允许将Java应用程序分解为多个模块,以提供更好的隔离性和可维护性。模块化系统通过模块描述文件(module-info.java)定义模块的依赖关系,并使用模块路径(module-path)指定模块的查找位置。

内存模型

JVM的内存模型包括运行时数据区和PC寄存器。

  1. :所有线程共享的内存区域,用于存放几乎所有的对象实例和数组。堆内存是动态分配的,其大小可以通过JVM参数进行调整。

  2. :每个线程拥有的独立内存空间,用于存放线程的局部变量和方法调用栈。栈内存的大小是固定的,通常在创建线程时指定。

  3. 方法区:用于存放已被虚拟机加载的类信息、常量、静态变量等数据。方法区的大小也是固定的,通常在JVM启动时指定。

  4. PC寄存器:用于存储当前线程所执行的指令的地址。PC寄存器的大小与处理器架构有关。

内存溢出场景分析

内存溢出是指JVM内存不足,无法分配新的内存给对象或数组时发生的情况。常见的内存溢出场景包括:

  • 创建对象过多:在短时间内创建大量对象,导致内存占用急剧增加。
  • 大型数组创建:创建大型数组,如int[] arr = new int[1000000000];,可能导致内存不足。
  • 循环引用:循环引用会导致对象无法被垃圾回收,从而占用内存。
垃圾回收

垃圾回收(GC)是JVM自动回收不再使用的对象所占用的内存空间的过程。垃圾回收的触发条件包括:

  • 系统空闲时间达到设定阈值
  • 老年代空间不足
  • 新生代空间不足

垃圾回收算法主要包括标记-清除、复制和标记-整理算法。

  • 标记-清除:先标记所有可达对象,然后清除未被标记的对象。这种算法容易产生内存碎片。
  • 复制:将内存分为两个部分,每次只使用其中一部分,当这部分空间不足时,将存活对象复制到另一部分,并清空原空间。这种算法避免了内存碎片,但牺牲了内存利用率。
  • 标记-整理:在标记-清除算法的基础上,对内存进行整理,避免内存碎片。
GC Roots可达性分析

GC Roots是垃圾回收算法中的一个重要概念,它指的是从GC Roots开始,能够通过引用关系访问到的对象。只有当对象无法通过GC Roots访问时,才被认为是垃圾对象。常见的GC Roots包括:

  • 栈帧中的本地变量表
  • 方法区中的静态变量
  • 方法区中的常量池
  • 虚引用、弱引用和软引用的对象
  • 反射创建的对象
  • JNI本地方法创建的对象
分代收集理论

分代收集理论将JVM内存分为新生代(Young)和老年代(Old),分别采用不同的垃圾回收策略。

  • 新生代:用于存放新创建的对象,采用复制算法或标记-清除算法。新生代空间较小,回收频率较高。
  • 老年代:用于存放生命周期较长的对象,采用标记-清除、标记-整理或并发收集算法。老年代空间较大,回收频率较低。
引用类型

引用类型包括强引用、软引用、弱引用和虚引用。

  • 强引用:最普通的引用类型,垃圾回收器不会回收强引用的对象。例如,Object obj = new Object();就是一个强引用。
  • 软引用:用于缓存,当内存不足时,垃圾回收器会回收软引用的对象。例如,SoftReference<Object> softRef = new SoftReference<>(obj);就是一个软引用。
  • 弱引用:与软引用类似,但垃圾回收器会立即回收弱引用的对象。例如,WeakReference<Object> weakRef = new WeakReference<>(obj);就是一个弱引用。
  • 虚引用:没有任何实际意义,用于跟踪对象被回收的情况。例如,PhantomReference<Object> phantomRef = new PhantomReference<>(obj, null);就是一个虚引用。
垃圾回收算法

垃圾回收算法主要包括标记-清除、复制和标记-整理算法。

  • 标记-清除:先标记所有可达对象,然后清除未被标记的对象。这种算法容易产生内存碎片。
  • 复制:将内存分为两个部分,每次只使用其中一部分,当这部分空间不足时,将存活对象复制到另一部分,并清空原空间。这种算法避免了内存碎片,但牺牲了内存利用率。
  • 标记-整理:在标记-清除算法的基础上,对内存进行整理,避免内存碎片。
并发收集器

并发收集器允许垃圾回收与应用程序的运行同时进行,减少应用程序的停顿时间。

  • CMS(Concurrent Mark Sweep):以最短停顿时间为目标,适用于对停顿时间要求较高的场景。CMS算法分为四个阶段:初始标记、并发标记、重新标记和并发清除。
  • G1(Garbage-First):将堆内存划分为多个区域,优先回收垃圾回收价值最高的区域。G1算法分为多个阶段:初始标记、根区域扫描、并发标记、重新标记、混合收集和并发清理。
  • ZGC(Z Garbage Collector):适用于多核处理器,以低延迟为目标。ZGC算法分为多个阶段:并发标记、并发垃圾回收和并发重置。
停顿时间控制策略

停顿时间控制策略包括:

  • 最大停顿时间目标:设定一个最大停顿时间,垃圾回收器会尽量满足这个目标。
  • 自适应停顿时间:根据应用程序的运行情况动态调整停顿时间。
性能调优

性能调优主要包括:

  • JVM参数配置:通过调整JVM参数(如Xms、Xmx等)来优化性能。例如,可以设置堆内存大小、栈内存大小、垃圾回收策略等。
  • 内存泄漏诊断:使用工具检测内存泄漏,并修复相关代码。常见的内存泄漏检测工具包括JProfiler、MAT等。
JIT编译优化

JIT编译器是JVM的一个重要组成部分,它负责将Java字节码编译成本地机器码,以提高程序执行效率。JIT编译器采用多种优化技术,例如:

  • 常量折叠:将常量表达式在编译时进行计算,避免在运行时重复计算。
  • 内联:将小的方法调用替换为方法体,减少方法调用的开销。
  • 循环优化:优化循环结构,减少循环的开销。
  • 分支预测:预测分支的执行方向,减少分支预测错误的开销。

Spring Boot知识体系概述

Spring Boot是一个开源的Java-based框架,用于简化Spring应用的初始搭建以及开发过程。以下是Spring Boot知识体系的详细解析。

自动配置

Spring Boot的自动配置功能可以根据类路径下添加的jar依赖自动配置Spring框架的相关功能。自动配置的实现依赖于条件化配置(@Conditional)和条件注解(@ConditionalOnClass、@ConditionalOnMissingBean等)。

@EnableAutoConfiguration原理

@EnableAutoConfiguration注解是Spring Boot自动配置的核心,它通过扫描类路径下的jar依赖,自动配置相应的Bean。SpringFactoriesLoader类负责加载类路径下META-INF/spring.factories文件中的自动配置类。

条件化配置(@Conditional)

条件化配置允许开发者根据特定的条件来决定是否应用某些配置。常见的条件注解包括:

  • @ConditionalOnClass:当指定的类在类路径下存在时,应用配置。
  • @ConditionalOnMissingBean:当指定的Bean不存在时,应用配置。
  • @ConditionalOnProperty:当指定的属性值满足条件时,应用配置。
自定义Starter开发

自定义Starter允许开发者将特定的功能封装成jar包,方便其他开发者使用。自定义Starter需要创建一个Maven项目,并添加Spring Boot的依赖和自动配置类。

起步依赖、依赖管理机制

起步依赖是Spring Boot中用于简化依赖管理的概念,它将多个jar依赖打包成一个jar包。起步依赖通常以spring-boot-starter-开头,例如spring-boot-starter-web、spring-boot-starter-data-jpa等。

版本冲突解决

解决版本冲突的方法包括:

  • 使用BOM文件(Bill of Materials)来管理依赖版本。BOM文件定义了所有依赖的版本信息,确保应用程序中使用的依赖版本一致。
  • 使用依赖锁定策略。依赖锁定策略可以锁定特定版本的依赖,避免版本冲突。
第三方库集成模式

第三方库集成模式包括:

  • 使用Spring Boot的自动配置功能。Spring Boot的自动配置功能可以自动配置第三方库,例如数据库连接池、缓存等。
  • 手动配置Bean。通过配置Bean的方式集成第三方库,例如配置数据库连接池、缓存等。
Actuator、健康检查端点

Actuator是Spring Boot提供的一个端点,用于监控和管理应用程序。Actuator提供了多个端点,例如/health、/metrics、/info等。

度量指标收集

度量指标收集是指收集应用程序的性能数据,例如内存使用情况、线程数等。Spring Boot提供了Micrometer框架,用于收集和导出度量指标。

自定义Endpoint开发

自定义Endpoint允许开发者根据需求添加新的端点。自定义Endpoint需要继承org.springframework.boot.actuate.endpoint.Endpoint接口,并实现invoke方法。

配置文件管理

Spring Boot支持多种配置文件格式,例如application.yml和application.properties。配置文件可以定义应用程序的属性,例如数据库连接信息、缓存配置等。

多环境配置

多环境配置允许开发者为不同的环境(如开发、测试、生产)配置不同的配置文件。Spring Boot支持通过配置文件名区分不同环境的配置,例如application-dev.yml、application-test.yml、application-prod.yml。

配置加载优先级

配置加载优先级是指Spring Boot如何加载多个配置文件。Spring Boot会按照以下顺序加载配置文件:

  1. 根配置文件(例如:application.yml)
  2. 环境配置文件(例如:application-dev.yml)
  3. 指定配置文件(例如:application-dev.properties)
动态配置刷新

动态配置刷新允许开发者实时更新配置文件,而无需重启应用程序。Spring Boot支持通过Actuator端点实现动态配置刷新。

监控与日志

Spring Boot提供了一系列监控和日志功能,例如Actuator和Logback。Actuator可以监控应用程序的性能数据,而Logback可以配置日志级别和输出格式。

Micrometer集成

Micrometer是一个度量指标收集框架,可以与多种监控系统集成。Micrometer支持多种监控服务,例如Prometheus、Grafana等。

Logback/SLF4J配置

Logback和SLF4J是Java日志框架,Spring Boot支持它们的集成。Logback提供了丰富的日志级别和输出格式,而SLF4J提供了统一的日志接口。

分布式链路追踪

分布式链路追踪是指追踪分布式系统中各个组件之间的调用关系。Spring Boot支持使用Zipkin、Jaeger等分布式链路追踪工具。

扩展机制

Spring Boot提供了一系列扩展机制,例如自定义AutoConfigurationBean和生命周期扩展点。

响应式编程支持

Spring Boot支持响应式编程,例如使用Spring WebFlux框架。响应式编程可以提供更好的并发性能和可扩展性。

通过以上对JVM和Spring Boot知识体系的详细解析,我们可以看到这两个技术是如何相互关联和相互影响的。JVM作为Java语言的运行环境,为Spring Boot提供了基础,而Spring Boot则构建在JVM之上,提供了丰富的功能来简化Java应用的开发。在实际开发过程中,了解这两个技术的内在联系,将有助于我们更好地构建高性能、可维护的Java应用。

优快云

博主分享

📥博主的人生感悟和目标

Java程序员廖志伟

📙经过多年在优快云创作上千篇文章的经验积累,我已经拥有了不错的写作技巧。同时,我还与清华大学出版社签下了四本书籍的合约,并将陆续出版。

面试备战资料

八股文备战
场景描述链接
时间充裕(25万字)Java知识点大全(高频面试题)Java知识点大全
时间紧急(15万字)Java高级开发高频面试题Java高级开发高频面试题

理论知识专题(图文并茂,字数过万)

技术栈链接
RocketMQRocketMQ详解
KafkaKafka详解
RabbitMQRabbitMQ详解
MongoDBMongoDB详解
ElasticSearchElasticSearch详解
ZookeeperZookeeper详解
RedisRedis详解
MySQLMySQL详解
JVMJVM详解

集群部署(图文并茂,字数过万)

技术栈部署架构链接
MySQL使用Docker-Compose部署MySQL一主二从半同步复制高可用MHA集群Docker-Compose部署教程
Redis三主三从集群(三种方式部署/18个节点的Redis Cluster模式)三种部署方式教程
RocketMQDLedger高可用集群(9节点)部署指南
Nacos+Nginx集群+负载均衡(9节点)Docker部署方案
Kubernetes容器编排安装最全安装教程

开源项目分享

项目名称链接地址
高并发红包雨项目https://gitee.com/java_wxid/red-packet-rain
微服务技术集成demo项目https://gitee.com/java_wxid/java_wxid

管理经验

【公司管理与研发流程优化】针对研发流程、需求管理、沟通协作、文档建设、绩效考核等问题的综合解决方案:https://download.youkuaiyun.com/download/java_wxid/91148718

希望各位读者朋友能够多多支持!

现在时代变了,信息爆炸,酒香也怕巷子深,博主真的需要大家的帮助才能在这片海洋中继续发光发热,所以,赶紧动动你的小手,点波关注❤️,点波赞👍,点波收藏⭐,甚至点波评论✍️,都是对博主最好的支持和鼓励!

🔔如果您需要转载或者搬运这篇文章的话,非常欢迎您私信我哦~

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值