JVM详解

什么是JVM

JVM是Java Virtual Machine(Java虚拟机)的缩写,JVM是一种用于计算设备的规范,它是一个虚构出来的计算机,是通过在实际的计算机上仿真模拟各种计算机功能来实现的。
引入Java语言虚拟机后,Java语言在不同平台上运行时不需要重新编译。Java语言使用Java虚拟机屏蔽了与具
体平台相关的信息,使得Java语言编译程序只需生成在Java虚拟机上运行的目标代码(字节码),就可以在多种平台上不加修改地运行。

Java为什么是“平台无关的编程语言”

Java虚拟机是一个可以执行Java字节码的虚拟机进程。
Java源文件被编译成能被Java虚拟机执行的字节码文件(.class文件)。
Java被设计成允许应用程序可以运行在任意的平台,而不需要程序员为每一个平台单独重写或者是重新编译。
Java虚拟机让这个变为可能,因为它知道底层硬件平台的指令长度和其他特性。

JRE/JDK/JVM是什么关系

JRE是Java运行环境,即(Java Runtime Environment),也就是Java平台。所有的Java程序都要在JRE下才能运行。
JDK是开发工具包,即(Java Development Kit),它是程序开发者用来编译、调试Java程序,它也是Java
程序,也需要JRE才能运行。
JVM是Java虚拟机,即(Java Virual Machine),它是JRE的一部分,一个虚构出来的计算机,它支持跨平台。

小结

Java虚拟机成为jvm,它是分离了一部分真实电脑的资源。我们写的Java程序都是在JVM上运行的,不是在真实的计算机上运行。
程序员写程序 -> JVM ->真实的计算机。
JVM解决了各操作系统兼容性问题。
目前最新版本是jdk22,使用版本一般是JDK8,JDK只有3个版本是商用免费的,即8、11、17。
JDK:开发和运行 ,其中包含了JRE,可以将.java文件 字节 为.class文件。
JRE:运行环境,其中包含JVM,运行.class文件。
JVM:通过运行.class文件去调用底层操作系统。
三种JVM:
① Sun公司的HotSpot;
② BEA公司的JRockit;
③ IBM公司的J9 JVM;
在JDK1.7及其以前我们所使用的都是Sun公司的HotSpot,但由于Sun公司和BEA公司都被oracle收购,
jdk1.8将采用Sun公司的HotSpot和BEA公司的JRockit两个JVM中精华形成jdk1.8的JVM。

JVM原理

JVM是Java核心和基础,在Java编译器和os平台之间的虚拟处理器,可以在上面执行Java的字节码程序。Java编译器主要面向JVM,生成JVM能理解的代码或字节码文件。Java源文件经编译成字节码程序,通过JVM将每一条指令翻译成不同平台的机器码,通过特定平台运行。

JVM体系结构

类加载器:加载class文件。
执行引擎:执行字节码或者执行本地方法。
运行时数据区:包括方法区、堆、Java栈、PC寄存器、本地方法栈。

JVM运行时数据区

1.类加载器(ClassLoader):在JVM启动时或者在类运行时将需要的class加载到JVM中。
2.执行引擎:负责执行class文件中包含的字节码指令
3.内存区(也叫运行时数据区)是在JVM运行的时候操作所分配的内存区。
运行时内存区主要可以划分为6个区域:
PC寄存器:用于存储每个线程下一步将执行的JVM指令。
:栈是线程私有的,每个线程创建的同时都会创建JVM栈,JVM栈中存放当前线程中的局部基本类型的变量。
:是JVM用来存储对象实例以及数组值的区域,可以认为Java中所有通过new创建的对象的内存都在此分配,Heap中的对象的内存需要等待GC进行回收。堆是JVM所有线程共享的。
方法区:存放了所加载的类信息(名称、修饰符等)、类中的静态变量、类中定义为final类型的常量、类中的Field信息、类中的方法信息;通过class对象中的getName等方法来获取信息时,实际这些数据是来源于方法区,方法区是全局共享的。
运行时常量池:存放类中固定的常量信息、方法和Field的引用信息等,其空间是从方法区中分配。
本地方法栈:JVM采用本地方法栈来支持native方法的执行,此区域用于存储每个native方法调用的状
态。

加载顺序

在这里插入图片描述
在这里插入图片描述

方法区(Method Area):用于存储类结构信息的地方,包括常量池、静态变量、构造函数等。虽然JVM规范把方法区描述为堆的一个逻辑部分, 但它却有个别名non-heap(非堆)。方法区还包含一个运行时常量池。
java堆(Heap):存储java实例或者对象的地方。这块是GC的主要区域(GC具体相关请查看之前的文章)。从存储的内容可以很容易知道,方法区和堆是被所有java线程共享的
java栈(Stack):java栈总是和线程关联在一起,每当创建一个线程时,JVM就会为这个线程创建一个对应的java栈。在这个java栈中又会包含多个栈帧,每运行一个方法就创建一个栈帧,用于存储局部变量表、操作
栈、方法返回值等。每一个方法从调用直至执行完成的过程,就对应一个栈帧在java栈中入栈到出栈的过程。所以java栈是线程私有的
程序计数器(PC Register):用于保存当前线程执行的内存地址。由于JVM程序是多线程执行的(线程轮流切换),所以为了保证线程切换回来后,还能恢复到原先状态,就需要一个独立的计数器,记录之前中断的地方,可见程序计数器也是线程私有的
本地方法栈(Native Method Stack):和java栈的作用差不多,只不过是为JVM使用到的native方法服务的。
本地方法接口:主要是调用C或C++实现的本地方法及返回结果。
扩展一个小知识:

如何判断对象是否存活

引用计数法:给对象中添加一个引用计数器,当一个地方引用了对象,计数加1;当引用失效,计数器减
1;当计数器为0表示该对象已死、可回收;但很难解决循环引用问题;
可达性分析:通过一系列称为“GC Root”的对象作为起点,从这些节点开始向下搜索,搜索所走过的路径
称为引用链,当一个对象GC Roots没有任何引用链相连,则证明此对象已死、可回收。
Java中可以作为GC Roots的对象包括:
虚拟机栈中引用的对象、本地方法栈中native方法引用的对象、方法区静态属性引用的对象、方法区常量引用的对象

总结

线程共享:方法区、堆
线程私有:java栈、本地方法栈、程序计数器
①堆空间(Heap):
存放创建出来的对象、对象中的属性,是共享的。
是Java虚拟机所管理的内存中最大的一块,在虚拟机启动时创建。线程共享,此内存区域的唯一目的就是存放
对象实例。
②方法区(Method Area):
存放方法、常量、静态变量、构造函数、字符串常量池,是共享的。
用于存储已被虚拟机加载的类信息、常量、静态变量、即时编译器编译后的代码等数据。
③栈区(JVM Stacks):
存放局部变量、方法的调用过程(栈帧)、方法的返回值,栈中的数据会随着栈的使用结束而销毁,是线程私有,生命周期与线程相同。
虚拟机栈描述的是Java方法执行的内存模型:每个方法被执行的时候都会同时创建一个栈帧(Stack Frame)
用于存储局部变量表、操作栈、动态链接、方法出口等信息。每一个方法被调用直至执行完成的过程,就对应着一个栈帧在虚拟机栈中从入栈到出栈的过程。
④程序计数器(Program Counter Register):
多线程切换执行时,保证每个线程都能正常切换。
线程私有,是一块较小的内存空间,它的作用可以看做是当前线程所执行的字节码的行号指示器。
⑤本地方法区(Native Method Stacks):
线程私有,与虚拟机栈所发挥的作用是非常相似的,其区别不过是虚拟机栈为虚拟机执行Java方法(也就是字节码)服务,而本地方法栈则是为虚拟机使用到的Native方法服务。
注: Native Method就是一个java调用非java代码的接口。

<think>好的,我需要回答用户关于JVM工作原理和性能调优方法的问题。首先,我得回顾一下JVM的基本结构和工作机制,确保自己理解正确。JVM主要包括类加载子系统、运行时数据区、执行引擎和本地库接口这几个部分。运行时数据区又分为方法区、堆、虚拟机栈、本地方法栈和程序计数器。其中堆是垃圾回收的重点区域,分为新生代和老年代。 接下来是性能调优部分。用户可能想知道具体怎么调整参数,比如堆内存大小、新生代和老年代的比例。常见的调优参数有-Xms、-Xmx设置堆的初始和最大大小,-XX:NewRatio调整新生代和老年代的比例。另外,垃圾回收器的选择也很重要,比如Serial、Parallel、CMS、G1和ZGC,每种都有适用场景。 用户提供的引用中有提到性能调优的步骤,比如监控分析、参数调整、优化代码等。需要结合这些内容,给出系统化的建议。例如,先用监控工具如jstat、VisualVM分析内存使用和GC情况,再根据结果调整参数,可能还需要优化代码减少内存泄漏。 另外,引用里提到的书籍和工具,比如《深入理解Java虚拟机》和Universal JVM GC analyzer,可以作为推荐的参考资料,增强回答的权威性。要注意引用标识的正确添加,比如在提到调优步骤时引用[^1][^2],书籍推荐时引用[^3]。 用户的问题还要求生成相关问题,我需要根据JVM的结构和调优方法,提出几个相关的问题,比如调优步骤、内存模型、垃圾回收算法比较等。确保问题有针对性,帮助用户进一步学习。 最后,检查回答是否符合格式要求:使用中文,数学表达式正确,引用标识自然添加,结构清晰。确保没有使用Markdown,语言口语化,分步骤解释,逻辑连贯。</think>### JVM工作原理与性能调优指南 #### 一、JVM核心工作原理 1. **类加载机制** JVM通过类加载子系统(ClassLoader)加载字节码文件(.class),包含以下步骤: - **加载**:查找并读取类文件 - **验证**:确保字节码符合规范 - **准备**:为静态变量分配内存 - **解析**:将符号引用转为直接引用 - **初始化**:执行静态代码块和赋值操作 2. **运行时数据区** - **方法区**:存储类信息、常量池等(JDK 8后由元空间实现) - **堆**:对象实例的存储区域(分为新生代和老年代) - **虚拟机栈**:存储方法调用的栈帧(局部变量、操作数栈等) - **本地方法栈**:服务于Native方法 - **程序计数器**:记录当前线程执行位置 3. **垃圾回收(GC)** - **分代收集**:新生代使用复制算法(如Minor GC),老年代使用标记-清除或标记-整理算法(如Full GC) - **可达性分析**:通过GC Roots(如栈中引用、静态变量)判断对象存活 4. **执行引擎** 将字节码解释为机器码或通过即时编译器(JIT)优化热点代码[^3]。 --- #### 二、JVM性能调优方法 1. **内存调优** - **堆内存设置**:通过`-Xms`(初始堆大小)、`-Xmx`(最大堆大小)避免频繁扩容 - **新生代与老年代比例**:`-XX:NewRatio=3`表示老年代是新生代的3倍 - **元空间限制**:`-XX:MaxMetaspaceSize`防止元空间无限增长 2. **垃圾回收器选择** | 回收器 | 适用场景 | 参数示例 | |-------------------|-----------------------------------|-------------------------| | Serial GC | 单线程、小内存应用 | `-XX:+UseSerialGC` | | Parallel GC | 多核CPU、高吞吐量 | `-XX:+UseParallelGC` | | CMS GC | 低延迟应用 | `-XX:+UseConcMarkSweepGC` | | G1 GC | 大堆内存、可预测停顿 | `-XX:+UseG1GC` | | ZGC | 超低延迟(JDK 15+) | `-XX:+UseZGC` | 3. **监控与分析工具** - **命令行工具**:`jstat`(GC统计)、`jmap`(堆转储) - **可视化工具**:VisualVM、JConsole - **GC日志分析**:添加`-Xloggc:<file>`记录日志,使用工具如[Universal JVM GC analyzer][^4]解析 4. **常见调优策略** - **减少Full GC频率**:优化对象生命周期,避免内存泄漏 - **调整线程栈大小**:`-Xss`防止栈溢出或内存浪费 - **禁用偏向锁**:高并发场景下使用`-XX:-UseBiasedLocking` --- #### 三、调优步骤示例 1. **监控基线性能**:使用`jstat -gcutil <pid> 1000`观察GC频率 2. **分析内存泄漏**:通过`jmap -histo:live <pid>`查看对象分布 3. **调整参数**:若Minor GC频繁,增加`-Xmn`(新生代大小) 4. **验证优化效果**:对比调优前后的吞吐量和停顿时间[^1]。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值