深入理解Java虚拟机(JVM)

引言

Java虚拟机(JVM)是Java平台的核心组件,它负责将Java字节码转换成平台特定的机器指令,并在相应的硬件和操作系统上执行。JVM的引入使得Java语言具有“一次编写,到处运行”的跨平台特性。本文将深入探讨JVM的基本结构、内存模型、关键技术以及性能优化等方面的内容。

一、JVM的基本结构

JVM主要由类加载器、运行时数据区、执行引擎、垃圾收集器和本地接口几部分组成。
JVM的基本结构

  1. 类加载器:负责加载Java类的字节码到JVM中,并将其转换为可以被JVM执行的数据结构。
  2. 运行时数据区:包括方法区、堆、Java栈、程序计数器以及本地方法栈。这些区域在JVM进程启动时创建,并在JVM进程结束时销毁。
  3. 执行引擎:负责读取Java字节码,并对其进行解释或即时编译(JIT),生成本地机器代码并执行。
  4. 垃圾收集器:负责自动回收不再使用的内存空间,防止内存泄漏和溢出。
  5. 本地接口:负责与本地方法库进行交互,允许Java代码调用本地代码(如C、C++等)或被本地代码调用。

运行流程 :首先通过编译器把 Java 代码转换成字节码,类加载器(ClassLoader)再把字节码加载到内存中,将其放在运行时数据区(Runtime data area)的方法区内,而字节码文件只是 JVM 的一套指令集规范,并不能直接交给底层操作系统去执行,因此需要特定的命令解析器执行引擎(Execution Engine),将字节码翻译成底层系统指令,再交由 CPU 去执行,而这个过程中需要调用其他语言的本地库接口(Native Interface)来实现整个程序的功能。

二、JVM的内存模型

JVM(Java Virtual Machine)的内存模型是Java程序运行时管理内存的一套规则。它定义了Java程序在JVM中如何通过内存来交互和操作。以下是对JVM内存模型的详细描述:

  1. 堆(Heap)
    • 堆是JVM中最大的一块内存区域,用于存储对象实例以及数组。几乎所有的Java对象实例都在堆上分配。
    • java堆是垃圾收集器管理的主要区域,因此也被成为“GC堆”。堆内存可以进一步细分为新生代和老年代。新生代主要用于存储新创建的对象,而老年代则用于存储长时间存活的对象。新生代又可以分为Eden区、From Survivor区和To Survivor区。
    • 根据Java虚拟机规范的规定,java堆可以处于物理上不连续的内存空间中。当前主流的虚拟机都是可扩展的(通过 -Xmx 和 -Xms 控制)。如果堆中没有内存可以完成实例分配,并且堆也无法再扩展时,将会抛出OutOfMemoryError异常。
  2. 方法区(Method Area)(也称为元空间(Metaspace)在JDK 8及以后版本):
    • 方法区存储已被虚拟机加载的类信息、常量、静态变量、即时编译器编译后的代码等数据。
    • 在JDK 8之前,方法区被称为永久代(PermGen),但由于永久代的大小是固定的,容易引发OutOfMemoryError,因此在JDK 8中,方法区被元空间所取代,元空间使用的是直接内存,受本机总内存限制。
    • 直接内存(Direct Memory)并不是虚拟机运行时数据区的一部分,也不是Java虚拟机中定义的内存区域。但是这部分内存也被频繁地使用,而且也可能导致 OutOfMemoryError 异常出现,所以我们放到这里一起讲解。我的理解就是直接内存是基于物理内存和Java虚拟机内存的中间内存
  3. 虚拟机栈(Java Stack)(也称为线程栈):
    • 虚拟机栈是每个线程私有的内存区域,用于存储局部变量、操作数栈、动态链接和方法出口等信息。
    • 当一个方法被调用时,JVM会为该方法的局部变量在栈上分配内存空间,并在方法执行结束后自动释放这些内存空间。
    • 每个方法在执行的同时都会创建一个栈帧(StackFrame)。解析栈帧:
    1. 局部变量表:是用来存储我们临时8个基本数据类型、对象引用地址、returnAddress类型。(returnAddress中保存的是return后要执行的字节码的指令地址。)
    2. 操作数栈:操作数栈就是用来操作的,例如代码中有个 i = 6*6,他在一开始的时候就会进行操作,读取我们的代码,进行计算后再放入局部变量表中去。
    3. 动态链接:假如我方法中,有个 service.add()方法,要链接到别的方法中去,这就是动态链接,存储链接的地方。
    4. 方法出口:出口是什呢,出口正常的话就是return 不正常的话就是抛出异常。
  4. 本地方法栈(Native Method Stack)
    • 与虚拟机栈类似,本地方法栈也是线程私有的内存区域,但它主要用于支持本地方法(Native Method)的执行。
    • native关键字的方法是看不到的,必须要去oracle官网去下载才可以看的到。本地方法通常是由C或C++编写的,通过JNI(Java Native Interface)调用。
  5. 程序计数器(Program Counter Register)
    • 程序计数器是一个较小的内存空间,用于存储当前线程所执行的字节码的行号指示器。
    • 字节码解释器工作时通过改变这个计数器的值来选取下一条需要执行的字节码指令。
    • 由于Java虚拟机的多线程是通过线程轮流切换并分配处理器执行时间的方式来实现的,一个处理器都只会执行一条线程中的指令。因此,为了线程切换后能恢复到正确的执行位置,每条线程都有一个独立的程序计数器,各个线程之间计数器互不影响,独立存储。称之为“线程私有”的内存。程序计数器内存区域是虚拟机中唯一没有规定OutOfMemoryError情况的区域。

在JVM中,堆和方法区是共享区,可以被多个线程访问;而虚拟机栈、本地方法栈和程序计数器则是线程私有的,每个线程都有自己独立的内存空间。这样的设计有助于实现线程之间的数据隔离和并发控制。

三、JVM的关键技术

  1. 即时编译(JIT):为了提高Java程序的执行效率,JVM引入了即时编译技术。JIT编译器可以将热点代码(频繁执行的代码)编译成本地机器代码,从而提高执行速度。
  2. 垃圾收集器:JVM提供了多种垃圾收集器,如Serial、Parallel、CMS和G1等。不同的垃圾收集器适用于不同的应用场景,选择合适的垃圾收集器对于提高JVM性能至关重要。
  3. 热点探测:JVM通过热点探测技术识别出热点代码,以便JIT编译器进行编译优化。热点探测主要基于执行计数器和采样两种方式。
  4. 逃逸分析:逃逸分析是一种确定对象是否会在方法体外被引用的技术。通过逃逸分析,JVM可以优化对象的分配和回收策略,提高内存使用效率。

四、JVM性能优化

JVM(Java Virtual Machine)性能优化是确保Java应用程序高效运行的关键步骤。通过合理的配置和调优,可以显著提高JVM的吞吐量、减少垃圾收集(GC)停顿时间、提高响应速度等。以下是对JVM性能优化的详细描述:

  1. 堆内存设置

    • 设置合适的初始堆大小(-Xms)和最大堆大小(-Xmx),以避免频繁的GC和内存溢出。
    • 根据应用程序的特性和需求,调整新生代(Young Generation)和老年代(Old Generation)的比例。
  2. GC调优

    • 选择合适的垃圾收集器(GC)。不同的GC适用于不同的应用场景,如Parallel GC适用于吞吐量优先的场景,CMS GC适用于响应时间优先的场景。
    • 调整GC的触发条件和参数,如GC线程数、GC暂停时间目标等,以平衡吞吐量和响应时间。
    • 使用GC日志分析工具(如GCViewer、GC Easy等)监控和分析GC行为,以便及时发现问题并进行调优。
  3. JIT(Just-In-Time)编译器调优

    • 调整JIT编译器的参数,如编译阈值、内联策略、代码缓存大小等,以提高编译效率和代码执行效率。
    • 使用热点探测技术识别热点代码,以便JIT编译器进行针对性的优化。
  4. 代码优化

    • 编写高效、简洁的代码,避免不必要的内存分配和对象创建。
    • 使用合适的数据结构和算法来降低时间复杂度和空间复杂度。
    • 使用字符串连接池来重用字符串对象,减少内存分配和垃圾收集的开销。
  5. 线程调优

    • 调整线程池的大小和类型,以适应应用程序的并发需求。
    • 设置线程的优先级,以确保关键任务能够得到及时处理。
    • 使用线程同步和并发控制机制(如锁、信号量、CyclicBarrier等)来避免竞态条件和死锁等问题。
  6. 锁优化

    • 减少锁的持有时间,避免长时间持有锁导致其他线程阻塞。
    • 使用轻量级锁和偏向锁等高级锁技术来减少锁的竞争和开销。
    • 使用读写锁(ReadWriteLock)来允许多个线程同时读取共享资源,提高并发性能。
  7. 类加载优化

    • 优化类的加载过程,减少类的加载时间和内存占用。
    • 使用自定义类加载器来加载和管理特定类型的类。
  8. I/O优化

    • 使用NIO(New I/O)或AIO(Asynchronous I/O)来提高I/O操作的性能和效率。
    • 合理地使用缓冲区和缓存来减少I/O操作的次数和开销。
  9. 监控和诊断工具

    • 使用JVM监控和诊断工具(如JConsole、JVisualVM、JProfiler等)来监控和分析JVM的运行状态和性能瓶颈。
    • 根据监控结果调整JVM参数和代码实现,以提高性能。

总之,JVM性能优化是一个综合性的任务,需要从多个方面入手进行调优。通过合理的内存管理、并发性能优化、代码优化和监控诊断等手段,可以显著提高Java应用程序的性能和稳定性。

五、虚拟机类加载机制

  1. 类加载的机制及过程
    程序主动使用某个类时,如果该类还未被加载到内存中,则JVM会通过加载、连接、初始化3个步骤来对该类进行初始化。如果没有意外,JVM将会连续完成3个步骤,所以有时也把这个3个步骤统称为类加载或类初始化。
    类加载的过程
    1、加载
    加载指的是将类的class文件读入到内存,并将这些静态数据转换成方法区中的运行时数据结构,并在堆中生成一个代表这个类的java.lang.Class对象,作为方法区类数据的访问入口,这个过程需要类加载器参与。Java类加载器由JVM提供,是所有程序运行的基础,JVM提供的这些类加载器通常被称为系统类加载器。除此之外,开发者可以通过继承ClassLoader基类来创建自己的类加载器。类加载器,可以从不同来源加载类的二进制数据,比如:本地Class文件、Jar包Class文件、网络Class文件等等等。类加载的最终产物就是位于堆中的Class对象(注意不是目标类对象),该对象封装了类在方法区中的数据结构,并且向用户提供了访问方法区数据结构的接口,即Java反射的接口。

2、链接过程
当类被加载之后,系统为之生成一个对应的Class对象,接着将会进入连接阶段,连接阶段负责把类的二进制数据合并到JRE中(意思就是将java类的二进制代码合并到JVM的运行状态之中)。类连接又可分为如下3个阶段。

  1. 验证:确保加载的类信息符合JVM规范,没有安全方面的问题。主要验证是否符合Class文件格式规范,并且是否能被当前的虚拟机加载处理。
  2. 准备:正式为类变量(static变量)分配内存并设置类变量初始值的阶段,这些内存都将在方法区中进行分配。
  3. 解析:虚拟机常量池的符号引用替换为字节引用过程。

3、初始化
初始化阶段是执行类构造器 () 方法的过程。类构造器 ()方法是由编译器自动收藏类中的 所有类变量的赋值动作和静态语句块(static块)中的语句合并产生,代码从上往下执行。当初始化一个类的时候,如果发现其父类还没有进行过初始化,则需要先触发其父类的初始化虚拟机会保证一个类的 () 方法在多线程环境中被正确加锁和同步。

  1. 什么是类加载器,类加载器有哪些?
    类加载器
    实现通过类的权限定名获取该类的二进制字节流的代码块叫做类加载器。主要有一下四种类加载器:
  • 启动类加载器(Bootstrap ClassLoader)用来加载java核心类库,无法被java程序直接引用。
  • 扩展类加载器(extensions class loader):它用来加载 Java 的扩展库。Java 虚拟机的实现会提供一个扩展库目录。该类加载器在此目录里面查找并加载 Java 类。
  • 系统类加载器(system class loader):它根据 Java 应用的类路径(CLASSPATH)来加载Java 类。一般来说,Java 应用的类都是由它来完成加载的。可以通ClassLoader.getSystemClassLoader()来获取它。
  • 用户自定义类加载器,通过继承 java.lang.ClassLoader类的方式实现。
  1. 什么是双亲委派模型?
    如果一个类加载器收到了类加载的请求,它首先不会自己去加载这个类,而是把这个请求委派给父类加载器去完成,每一层的类加载器都是如此,这样所有的加载请求都会被传送到顶层的启动类加载器中,只有当父加载无法完成加载请求(它的搜索范围中没找到所需的类)时,子加载器才会尝试去加载类。

总结

JVM作为Java平台的核心组件,对于Java程序的性能和稳定性具有重要影响。了解JVM的基本结构、内存模型、关键技术以及性能优化等方面的知识,有助于我们更好地编写高效、稳定的Java程序。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/web/7844.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

ICC2:optimize_routability

我正在「拾陆楼」和朋友们讨论有趣的话题,你⼀起来吧? 拾陆楼知识星球入口 在postroute阶段,一些pin access引起的绕线问题,通常以end of line和short/spacing的形式扎堆出现,总量兴许不多,但是反复绕线仍难解决,返回preplace去设置keepout margin或placement label又得…

绘画作品3d数字云展厅提升大众的艺术鉴赏和欣赏能力

3D虚拟展厅作为未来艺术的展示途径,正逐渐成为文化创意产业蓬勃发展的重要引擎。这一创新形式不仅打破了传统艺术展览的局限性,更以其独特的魅力吸引着全球观众的目光。 3D虚拟艺术品展厅以其独特的魅力,助力提升大众的艺术鉴赏和欣赏能力。观…

什么是多模态大模型,有了大模型,为什么还要多模态大模型?

随着人工智能技术的愈演愈烈,其技术可以说是日新月异,每隔一段时间就会有新的技术和理念被创造出来;而多模态大模型也是其中之一。 什么是多模态 想弄明白什么是多模态大模型,那么首先就要弄明白什么是多模态。 简单来说&#x…

红海云OA存在任意文件上传漏洞【附poc】

漏洞复现 1、fofa poc见文末 body"RedseaPlatform" 打开burp进行抓包发送到repeater,如下图所示: 打入poc(文末获取),成功上传。 「你即将失去如下所有学习变强机会」 学习效率低,学不到实战内…

【Linux】基础命令

常用命令及参数:dir表示文件夹,file表示文件(file可表示其他目录下的文件) pwd命令;查看当前所属文件夹(print working directory) ls [选项] dir;查看当前、指定文件夹目录内容&am…

后仿真中的关于延时问题(物理特性角度)

大家都知道,后仿真讲究仿真时序。那么,在网表阶段,接触到后仿延时问题。今天总结一下。 一 延时概念和分类 1.1 分布式延迟(Distributed Delays) 一般用来指定模块内部信号通过逻辑单元或者线网耗费的时间。 1.2 模…

解决 idea代码不能自动提示功能

idea有可能没有代码提示,是非常不方便的,找了好几个办法,这个方法对了 如下输入psv或者psvm按下回车自动生成main方法,除此还有很多也可以代码提示,包括写好的接口调用,如果有对应的方法,输入也…

【iOS逆向与安全】网上gw如何自动登录与签到SM2,SM3,SM4算法加解密

1.下载 app 2.frida 调试 3.抓包查看接口 4.分析加密数据 5.易语言编写代码 1 .开始下载 下载好发现有越狱检测,检测点为: -[AppDelegate isJailBreak]; 于是编写插件xm代码 : %hook AppDelegate- (void)isJailBreak{NSLog("AppDelegate is…

JZ71 变态跳台阶

😀前言 本文探讨了一个有关青蛙跳台阶的变体问题,与传统的台阶跳跃不同,这只青蛙每次可以跳上任意多的台阶。我们需要解决的问题是:对于给定的台阶数,计算青蛙跳上该台阶的所有可能方法。本文将通过动态规划和数学推导…

如何获得一个Oracle 23ai数据库(Virtual Appliance)

准确的说,是Oracle 23ai Free Developer版,因为企业版目前只在云上(OCI和Azure)和ECC上提供。 方法包括3种,本文介绍第1种: Virtual ApplianceRPM安装Docker 从此处下载虚拟机。 可以看到虚拟机需要4G内…

力扣437. 路径总和 III

Problem: 437. 路径总和 III 文章目录 题目描述思路复杂度Code 题目描述 思路 1.定义int类型函数rootSum(root, targetSum),用于求取每一个节点等于目标函数的路径数: 1.1.易知rootSum(root, targetSum)求出的数量等于rootSum(root.left, targetSum - va…

2024年4月17日华为春招实习试题【三题】-题目+题解+在线评测,2024.4.17,华为机试

2024年4月17日华为春招实习试题【三题】-题目题解在线评测 🔮题目一描述:扑克牌消消乐输入描述输出描述样例一样例二Limitation解题思路一:模拟,遇到连续3张相同牌号的卡牌,直接删除解题思路二:栈解题思路三…

【notepad++】使用

1 notepad 下载路径 https://notepad-plus.en.softonic.com/download 2 设置护眼模式 . 设置——语言格式设置——前景色——黑色 . 背景色——RGB :199 237 204 . 勾选“使用全局背景色”、“使用全局前景色” . 保存并关闭

2009-2022年上市公司华证ESG评级评分数据(含细分项)

2009-2022年上市公司华证ESG评级评分数据(含细分项) 1、时间:2009-2022年 2、来源:华证ESG 3、指标:证券代码、证券简称、综合评级、年度、综合得分、E评级、E得分、S评级、S得分、G评级、G得分 4、范围&#xff1…

PXE 批量安装部署

目录 一、PEX批量部署优点 二、PXE:预启动执行环境 三、搭建PXE远程服务器 要想全自动安装 接下来请看步骤: 一、PEX批量部署优点 规模化:同时装配多台服务器自动化:安装系统 配置各种服务远程实现:不需要光盘&…

Buuctf-Misc题目练习

打开后是一个gif动图,可以使用stegsolve工具进行逐帧看。 File Format:文件格式 Data Extract:数据提取 Steregram Solve:立体试图 可以左右控制偏移 Frame Browser:帧浏览器 Image Combiner:拼图,图片拼接 所以可以知道我们要选这个Frame Browser …

SQL查询语句(二)逻辑运算关键字

上一篇文章中我们提到了条件查询除了一些简单的数学符号之外,还有一些用于条件判断的关键字,如逻辑判断 关键字AND,OR,NOT和范围查找关键字BETWEEN,IN等;下面我们来介绍一些这些关键字的用法以及他们所表达的含义。 目录 逻辑运算关键字 AND…

用户管理中心——数据库设计用户注册逻辑设计

用户管理中心——数据库设计&用户注册逻辑设计 规整项目目录1. 数据库自动生成器的使用实现基本的数据库操作(操作user表) 2. 注册逻辑的设计(1) 写注册逻辑(2) 实现(3) 测试代码 3. 遇到的问题 规整项目目录 utils–存放工具类,比如加密…

基于Springboot 的 Excel表格的导入导出

首先 &#xff0c;引入相关依赖EasyPOI <dependency><groupId>cn.afterturn</groupId><artifactId>easypoi-spring-boot-starter</artifactId><version>4.4.0</version></dependency> 编写实体类&#xff1a; Data AllArgs…

产品需求文档怎么写?超详细的产品需求文档PRD模板来了!

产品需求文档怎么写&#xff1f;如何写一份简洁明了、外行人看了就能秒懂的产品需求文档呢&#xff1f;今天这篇文章&#xff0c;就来和大家分享如何编写一份高质量的产品需求文档 PRD&#xff01; 下图是来自 boardmix 模板社区的「产品需求文档」模板&#xff0c;它给出了一…