深入理解Java虚拟机(JVM)

news2024/11/25 16:27:24

引言

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.coloradmin.cn/o/1651273.html

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

相关文章

安装nginx-1.25.5与ngx_http_headers_more_filter_module模块

#下载nginx的代码 curl -O http://nginx.org/download/nginx-1.25.5.tar.gz #下载headers-more-nginx-module代码 git clone https://github.com/openresty/headers-more-nginx-module#解压 tar -xzf nginx-1.25.5.tar.gzcd nginx-1.25.5#--add-dynamic-module 下载下来的目录 …

简单两步将Lllama、Qwen等开源大模型安装到自己的电脑上

现在已经有非常多优秀的开源大语言模型了,比如Command R、Mistral、Qwen、MiniMax、Baichuan、Phi3等,其中Lllama3和Qwen等已经和GPT4的性能比较接近了。 如果能把这些免费的开源大模型部署到本地电脑或手机上,可以完全自由的使用&#xff0…

前后端分离项目中的一些疑惑

1、前后端分离项目,浏览器发起请求后,请求的是前端服务器还是后端服务器? 在前后端分离的项目中,当浏览器发起请求时,它首先会请求的是前端服务器。 前后端分离的工作流程大致如下: 用户在浏览器中输入网…

[Algorithm][多源BFS][矩阵][飞地的数量][地图中的最高点][地图分析] + 多源BFS原理讲解 详细讲解

目录 0.原理讲解1.矩阵1.题目链接2.算法原理详解3.代码实现 2.飞地的数量1.题目链接2.算法原理详解3.代码实现 3.地图中的最高点1.题目链接2.算法原理详解3.代码实现 4.地图分析1.题目链接2.算法原理详解3.代码实现 0.原理讲解 注意:只要是用**BFS解决的最短路径问题…

淘宝数据分析——Python爬虫模式♥

大数据时代, 数据收集不仅是科学研究的基石, 更是企业决策的关键。 然而,如何高效地收集数据 成了摆在我们面前的一项重要任务。 本文将为你揭示, 一系列实时数据采集方法, 助你在信息洪流中, 找到…

每日OJ题_贪心算法三③_力扣45. 跳跃游戏 II(dp解法+贪心解法)

目录 力扣45. 跳跃游戏 II 解析代码1_动态规划 解析代码2_贪心 力扣45. 跳跃游戏 II 45. 跳跃游戏 II 难度 中等 给定一个长度为 n 的 0 索引整数数组 nums。初始位置为 nums[0]。 每个元素 nums[i] 表示从索引 i 向前跳转的最大长度。换句话说,如果你在 num…

如何设置ddns动态域名服务实现外网访问

在本地搭建好服务器,部署好web网站或其他应用后,需要在外网访问内网时,如何设置动态域名服务ddns,将主机的内网IP端口映射到外网访问,是我们需要面对的一个重要步骤。 内网发布外网,常见的有两种方案&…

C语言程序设计(三)

1、数据的两种表现形式 常量:其值不能被改变的量称为常量。 变量: 单撇号内只能包含一个字符。双撇号内可以包含一个字符串。 注意:要区分符号常量和变量,不要把符号常量误认为变量。符号常量不占内存只是一个临时符号,代表一个值,在预编译…

QT和Halcon联合编程--注意是Ubuntu--

1.在QT目录下面的.pro文件下,如图所示: 根据你电脑的haclon的安装路径,添加如下代码: INCLUDEPATH /opt/halcon/include LIBS -L/opt/halcon/lib/x64-linux -lhalconcpp 需要等待一下,QT需要进行加载 2.在头文件中…

【综述】碳达峰、碳中和、碳足迹

文章目录 概念定义 碳足迹计算 动力蓄电池碳足迹 服务应用 参考资料 概念定义 温室气体,大气层中自然存在的和由于人类活动产生的能够吸收和散发由地球表面、大气层和云层所产生的、波长在红外光谱内的辐射的气态成分。包括二氧化碳(CO2&#xff09…

HIVE简单数据查询

HIVE简单数据查询 1.where WHERE 过滤条件 between/ in / is NULL / IS NOT NULL / > < ! ... 如果多个存在多个过滤条件 可以用 AND OR 进行条件关联 或者是用NOT 进行条件结果取反 2.JOIN JOIN 内连接 左外连接 右外连接 自连接 满连接…

Unity 性能优化之LOD技术(十)

提示&#xff1a;仅供参考&#xff0c;有误之处&#xff0c;麻烦大佬指出&#xff0c;不胜感激&#xff01; 文章目录 LOD技术效果一、LOD技术是什么&#xff1f;二、LODGroup组件介绍三、LODGroup组件使用步骤添加组件添加模型 四、Project Settings中与LOD组件相关参数总结 L…

视觉图像信息处理与FPGA实现第九次作业——直方图均衡

RAM的B站视频解析 RAM的文档 一、65536x8位的单端口RAM timescale 1ns / 1ps //SPRF Single Port Read/Write Function //65535 是RAM中总的字数&#xff0c;也就是存储深度&#xff0c;X8表示每个字是8位的 module SPRF65536X8(Q,CLK,CEN,WEN,A,D );//输出寄存器Qoutput [7…

k8s集群统一设置时间

1 安装时间同步需要软件 yum install -y ntpdate2 设置时间 2.1 手动设置时间 date -s "20190712 18:30:50" hwclock --systohc2.2 在线更新时间 ntpdate 0.asia.pool.ntp.org # 强制把系统时间写入CMOS clock -w3 强制把系统时间写入CMOS hwclock作用与clock相…

N7552A是德科技N7552A电子校准件

181/2461/8938产品概述&#xff1a; 更小巧轻便的 2 端口模块&#xff0c;支持 3.5 mm 或 N 型 50 Ω 连接器&#xff0c;能够将校准时间缩短一半 特点 频率范围&#xff1a;直流至 9 GHz 使用 N 型或 3.5 mm 连接器 更小巧轻便的 2 端口电子校准件&#xff08;ECal&#xff…

电脑(爱好者) :基础知识1 了解你的电脑

读懂cpu 您想了解关于您的电脑的信息吗&#xff1f;CPuz是一款常用的系统信息工具&#xff0c;可以提供关于CPU、主板、内存等硬件信息的详细情况。您可以下载并运行该软件&#xff0c;然后查看您的电脑硬件配置信息。 图片来源于网络 CPU-Z 简介 CPU-Z 是一款功能强大且易于使…

迅为RK3568开发板资料说明4750+页专属文档专为3568编写

iTOP-3568开发板采用瑞芯微RK3568处理器&#xff0c;内部集成了四核64位Cortex-A55处理器。主频高达2.0Ghz&#xff0c;RK809动态调频。集成了双核心架构GPU&#xff0c;ARM G52 2EE、支持OpenGLES1.1/2.0/3.2、OpenCL2.0、Vulkan1.1、内嵌高性能2D加速硬件。 内置独立NPU,算力…

绝地求生:新型小队对决系统或将择日上线?

就在刚才&#xff0c;PUBG官博发布了一则短视频&#xff0c;视频内容为两只小队通过竞争积分排名产生不断地变化。 原文官博 视频内容 在这里我猜测为之前官方在2024工作计划视频中介绍过的新型小队对决系统&#xff1a; 据当时的介绍称&#xff1a;这个系统中&#xff0c;己方…

大数据基础工程技术团队4篇论文入选ICLR,ICDE,WWW

近日&#xff0c;由阿里云计算平台大数据基础工程技术团队主导的四篇时间序列相关论文分别被国际顶会ICLR2024、ICDE2024和WWW2024接收。 论文成果是阿里云与华东师范大学、浙江大学、南京大学等高校共同研发&#xff0c;涉及时间序列与智能运维结合的多个应用场景。包括基于P…

2024DCIC海上风电出力预测Top方案 + 光伏发电出力高分方案学习记录

海上风电出力预测 赛题数据 海上风电出力预测的用电数据分为训练组和测试组两大类&#xff0c;主要包括风电场基本信息、气象变量数据和实际功率数据三个部分。风电场基本信息主要是各风电场的装机容量等信息&#xff1b;气象变量数据是从2022年1月到2024年1月份&#xff0c;…