《架构师进阶系列》第1章:JVM整体架构与调优参数说明

简介: 《架构师进阶系列》第1章:JVM整体架构与调优参数说明

大家好,我是冰河~~

从今天开始,我们正式开始《架构师进阶系列》技术文的更新,在《架构师进阶系列》中,我们首先一起来探讨有关JVM的知识。

很多小伙伴都认为JVM的知识很难,很枯燥,不知道该如何学习,买了很多关于JVM的书籍,看了没几页就看不下去了,放到书架里“吃灰”了。

其实,在互联网这个行业中,谁掌握了底层的核心知识,谁就能在激烈的竞争环境中脱颖而出。JVM看起来很难,只要你掌握了学习JVM的规律和方法,吃透它,其实很简单的。

  点击卡片关注我

文章总体结构

本文中,我们将按照如下结构介绍JVM的整体架构和调优参数。

image.png

JVM的分类

这里,我们先来说说什么是VM吧,VM的中文含义为:虚拟机,指的是使用软件的方式模拟具有完整硬件系统功能、运行在一个完全隔离环境中的完整计算机系统,是物理机的软件实现。

常用的虚拟机有:VMWare、Virtual Box,Java Virtual Machine(JVM,Java虚拟机)。

这里,我们重点聊的就是JVM,Java虚拟机。看下图。

image.png

这张图看起来还是比较简单的,JVM运行于操作系统之上,操作系统是运行在计算机硬件上的。

关于JVM,其实有很多大厂开发了不同版本的JVM,比较知名的有:Sun  HotSpot VM、BEA JRockit VM、IBM J9 VM、 Azul VM、 Apache Harmony、 Google  Dalvik VM、 Microsoft JVM等等。

现在使用的比较多的JDK8版本就是Sun HotSpot VM与BEA JRockit VM合并之后开发出的JDK版本。

JVM的构成

JVM主要由三个子系统构成,分别为:类加载器子系统、运行时数据区(内存结构)和字节码执行引擎

image.gif

为了更好的理解JVM,我们来看一下JVM的全貌图。

image.png

当我们开发Java程序时,首先会编写.java文件,之后,会将.java文件编译成.class文件。

JVM中,会通过类装载子系统将.class文件的内容装载到JVM的运行时数据区,而JVM的运行时数据区又会分为:方法区、堆、栈、本地方法栈和程序计数器 几个部分。

在装载class文件的内容时,会将class文件的内容拆分为几个部分,分别装载到JVM运行时数据区的几个部分。其中,值得注意的是:程序计数器的作用是:记录程序执行的下一条指令的地址。

方法区也叫作元空间,主要包含了:运行时常量池、类型信息、字段信息、方法信息、类加载器的引用、对应的Class实例的引用等信息。

在JVM中,程序的执行是通过执行引擎进行的,执行引擎会调用本地方法的接口来执行本地方法库,进而完成整个程序逻辑的执行。

我们常说的垃圾收集器是包含在执行引擎中的,在程序的运行过程中,执行引擎会开启垃圾收集器,并在后台运行,垃圾收集器会不断监控程序运行过程中产生的内存垃圾信息,并根据相应的策略对垃圾信息进行清理。

这里,大家需要注意的是:栈、本地方法栈和程序计数器是每个线程运行时独占的,而方法区和堆是所有线程共享的。所以,栈、本地方法栈和程序计数器不会涉及线程安全问题,而方法区和堆会涉及线程安全问题。

方法区(元空间)

很多小伙伴一看到方法区三个字,脑海中的第一印象可能是存储方法的地方吧。

实则不然,方法区的另一个名字叫作元空间,相信不少小伙伴或多或少的听说过元空间。这个区域是JDK1.8中划分出来的。主要包含:运行时常量池、类型信息、字段信息、方法信息、类加载器的引用、对应的Class实例的引用等信息。方法区中的信息能够被多个线程共享。

例如,在程序中声明的常量、静态变量和有关于类的信息等的引用,都会存放在方法区,而这些引用所指向的具体对象 一般都会在堆中开辟单独的空间进行存储,也可能会在直接内存中进行存储

image.png

堆中主要存储的是实际创建的对象,也就是会存储通过new关键字创建的对象,堆中的对象能够被多个线程共享。堆中的数据不需要事先明确生存期,可以动态的分配内存,不再使用的数据和对象由JVM中的GC机制自动回收。对JVM的性能调优一般就是对堆内存的调优

Java中基本类型的包装类:Byte、Short、Integer、Long、Float、Double、Boolean、Character类型的数据是存储在堆中的。

堆一般会被分成年轻代和老年代。而年轻代又会被进一步分为1个Eden区和2个Survivor区。在内存分配上,如果保持默认配置的话,年轻代和老年代的内存大小比例为1  : 2,年轻代中的1个Eden区和2个Survivor区的内存大小比例为:8 : 1 : 1。

image.png

栈一般又叫作线程栈或虚拟机栈,一般存储的是局部变量。在Java中,每个线程都会有一个单独的栈区,每个栈中的元素都是私有的,不会被其他的栈所访问。栈中的数据大小和生存期都是确定的,存取速度比较快。

在Java中,所有的基本数据类型(byte、short、int、long、float、double、boolean、char)和引用变量(对象引用)都是在栈中的。一般情况下,线程退出或者方法退出时,栈中的数据会被自动清除

程序在执行过程中,会在栈中为不同的方法创建不同的栈帧,在栈帧中又包含了:局部变量表、操作数栈、动态链接和方法出口。

image.png

关于局部变量表、操作数栈、动态链接和方法出口的具体作用,会在《架构师进阶系列》中的后续文章中详细阐述。

栈中一般会存储对象的引用,这些引用所指向的具体对象一般都会在堆中开辟单独的地址空间进行存储,也有可能存储在直接内存中。

image.png

注意:这里说的是这些引用所指向的具体对象一般都会在堆中开辟单独的地址空间进行存储,也有可能存储在直接内存中。

因为在JVM中,如果开启了逃逸分析和标量替换,则可能不会再在堆上创建对象,可能会将对象直接分配到栈上,也可能不再创建对象,而是进一步分解对象中的成员变量,将其直接在栈上分配空间并赋值。

本地方法栈

本地方法栈相对来说比较简单,就是保存native方法进入区域的地址。

例如,在Java中创建线程,调用Thread对象的start()方法时,会通过本地方法start0()调用操作系统创建线程的方法。此时,本地方法栈就会保存start0()方法进入区域的内存地址。

程序计数器

程序计数器也叫作PC计数器,主要存储的是下一条将要执行的命令的地址。

JVM调优参数

在JVM中,主要是对堆(新生代)、方法区和栈进行性能调优。各个区域的调优参数如下所示。

  • 堆:-Xms、-Xmx
  • 新生代:-Xmn
  • 方法区(元空间):-XX:MetaspaceSize、-XX:MaxMetaspaceSize
  • 栈(线程):-Xss

为了更加直观的表述,我们可以将JVM的内存区域和对应的调优参数总结成下图所示。

image.png

在设置JVM启动参数时,需要特别注意方法区(元空间)的参数设置。

关于方法区(元空间)的JVM参数主要有两个:-XX:MetaspaceSize和-XX:MaxMetaspaceSize。

-XX:MetaspaceSize: 指的是方法区(元空间)触发Full GC的初始内存大小(方法区没有固定的初始内存大小),以字节为单位,默认为21M。达到设置的值时,会触发Full GC,同时垃圾收集器会对这个值进行修改。

如果在发生Full  GC时,回收了大量内存空间,则垃圾收集器会适当降低此值的大小;如果在发生Full  GC时,释放的空间比较少,则在不超过设置的-XX:MetaspaceSize值或者在没设置-XX:MetaspaceSize的值时不超过21M,适当提高此值。

-XX:MaxMetaspaceSize: 指的是方法区(元空间)的最大值,默认值为-1,不受堆内存大小限制,此时,只会受限于本地内存大小。

最后需要注意的是: 调整方法区(元空间)的大小会发生Full GC,这种操作的代价是非常昂贵的。如果发现应用在启动的时候发生了Full GC,则很有可能是方法区(元空间)的大小被动态调整了。

所以,为了尽量不让JVM动态调整方法区(元空间)的大小造成频繁的Full GC,一般将-XX:MetaspaceSize和-XX:MaxMetaspaceSize设置成一样的值。例如,物理内存8G,可以将这两个值设置为256M

最后,我们一起看下在物理内存8G的情况下,启动应用程序时,可以设置的JVM参数。当然,我这里给出的是一些经验值,实际部署到生产环境时,需要经过压测找到最佳的参数值。

  • 启动SpringBoot
java ‐Xms2048M ‐Xmx2048M ‐Xmn1024M ‐Xss512K ‐XX:MetaspaceSize=256M ‐XX:MaxMetaspaceSize=256M ‐jar xxx.jar
  • 启动Tomcat(Linux)

在Tomcat bin目录下catalina.sh文件里配置。

‐Xms2048M ‐Xmx2048M ‐Xmn1024M ‐Xss512K ‐XX:MetaspaceSize=256M ‐XX:MaxMetaspaceSize=256M
  • 启动Tomcat(Windows)

在Tomcat bin目录下catalina.bat文件里配置。

‐Xms2048M ‐Xmx2048M ‐Xmn1024M ‐Xss512K ‐XX:MetaspaceSize=256M ‐XX:MaxMetaspaceSize=256M

总结

今天,我们一起学习了JVM的整体架构和调优参数,主要包括:JVM的总体结构、JVM的分类、JVM的构成和调优参数。

你学会了吗?欢迎在文末留言说出你的想法,如果你有更好的见解,也可以在文末留言和大家交流。

好了,今天就到这儿吧,我是冰河,我们下期见~~

相关文章
|
机器学习/深度学习 人工智能 文件存储
Llama Nemotron:英伟达开源基于Llama架构优化的推理模型,253B参数持平DeepSeek R1!
NVIDIA推出的Llama Nemotron系列推理模型,基于Llama架构优化,包含Nano/Super/Ultra三款,在数学推理、编程和工具调用等任务中展现卓越性能。
510 5
Llama Nemotron:英伟达开源基于Llama架构优化的推理模型,253B参数持平DeepSeek R1!
|
消息中间件 运维 监控
加一个JVM参数,让系统可用率从95%提高到99.995%
本文针对一个高并发(10W+ QPS)、低延迟(毫秒级返回)的系统因内存索引切换导致的不稳定问题,深入分析并优化了JVM参数配置。通过定位问题根源为GC压力大,尝试了多种优化手段:调整MaxTenuringThreshold、InitialTenuringThreshold、AlwaysTenure等参数让索引尽早晋升到老年代;探索PretenureSizeThreshold和G1HeapRegionSize实现索引直接分配到老年代;加速索引复制过程以及升级至JDK11使用ZGC。
810 82
加一个JVM参数,让系统可用率从95%提高到99.995%
Java程序员必学:JVM架构完全解读
Java 虚拟机(JVM)是 Java 编程的核心,深入理解其架构对开发者意义重大。本文详细解读 JVM 架构,涵盖类加载器子系统、运行时数据区等核心组件,剖析类加载机制,包括加载阶段、双亲委派模型等内容。阐述内存管理原理,介绍垃圾回收算法与常见回收器,并结合案例讲解调优策略。还分享 JVM 性能瓶颈识别与调优方法,分析 Java 语言特性对性能的影响,给出数据结构选择、I/O 操作及并发同步处理的优化技巧,同时探讨 JVM 安全模型与错误处理机制,助力开发者提升编程能力与程序性能。
Java程序员必学:JVM架构完全解读
|
机器学习/深度学习 人工智能 算法
超越 DeepSeek-R1!Seed-Thinking-v1.5:字节跳动开源MoE架构推理模型,200B总参数仅激活20B,推理效率提升5倍
字节跳动推出的200B参数混合专家模型,在AIME/Codeforces/GPQA等基准测试中实现多项突破,采用强化学习框架与流式推理系统,支持7大领域复杂推理任务。
909 13
超越 DeepSeek-R1!Seed-Thinking-v1.5:字节跳动开源MoE架构推理模型,200B总参数仅激活20B,推理效率提升5倍
|
机器学习/深度学习 编解码 人工智能
Kimi开源MoE架构多模态推理模型,小激活参数,大能量!
最近Moonshot AI推出了 Kimi-VL,这是一个高效的开源混合专家(MoE)视觉-语言模型(VLM),它提供了先进的多模态推理、长上下文理解以及强大的代理能力——所有这些功能都只需激活其语言解码器中的2.8B参数(Kimi-VL-A3B)。
982 1
|
监控 Java 编译器
Java虚拟机调优指南####
本文深入探讨了Java虚拟机(JVM)调优的精髓,从内存管理、垃圾回收到性能监控等多个维度出发,为开发者提供了一系列实用的调优策略。通过优化配置与参数调整,旨在帮助读者提升Java应用的运行效率和稳定性,确保其在高并发、大数据量场景下依然能够保持高效运作。 ####
414 58
|
监控 架构师 Java
Java虚拟机调优的艺术:从入门到精通####
本文作为一篇深入浅出的技术指南,旨在为Java开发者揭示JVM调优的神秘面纱,通过剖析其背后的原理、分享实战经验与最佳实践,引领读者踏上从调优新手到高手的进阶之路。不同于传统的摘要概述,本文将以一场虚拟的对话形式,模拟一位经验丰富的架构师向初学者传授JVM调优的心法,激发学习兴趣,同时概括性地介绍文章将探讨的核心议题——性能监控、垃圾回收优化、内存管理及常见问题解决策略。 ####
|
人工智能 Java 数据处理
Java高级应用开发:基于AI的微服务架构优化与性能调优
在现代企业级应用开发中,微服务架构虽带来灵活性和可扩展性,但也增加了系统复杂性和性能瓶颈。本文探讨如何利用AI技术,特别是像DeepSeek这样的智能工具,优化Java微服务架构。AI通过智能分析系统运行数据,自动识别并解决性能瓶颈,优化服务拆分、通信方式及资源管理,实现高效性能调优,助力开发者设计更合理的微服务架构,迎接未来智能化开发的新时代。
|
SQL 存储 关系型数据库
MySQL进阶突击系列(01)一条简单SQL搞懂MySQL架构原理 | 含实用命令参数集
本文从MySQL的架构原理出发,详细介绍其SQL查询的全过程,涵盖客户端发起SQL查询、服务端SQL接口、解析器、优化器、存储引擎及日志数据等内容。同时提供了MySQL常用的管理命令参数集,帮助读者深入了解MySQL的技术细节和优化方法。
JVM内存参数
-Xmx[]:堆空间最大内存 -Xms[]:堆空间最小内存,一般设置成跟堆空间最大内存一样的 -Xmn[]:新生代的最大内存 -xx[use 垃圾回收器名称]:指定垃圾回收器 -xss:设置单个线程栈大小 一般设堆空间为最大可用物理地址的百分之80