Java虚拟机(JVM)介绍

news2024/11/26 9:41:36

7a34bba3e436432f98a97feac69e20dc.jpgJVM是什么

 

JVM是Java Virtual Machine的缩写。它是一种基于计算设备的规范,是一台虚拟机,即虚构的计算机。

 

JVM屏蔽了具体操作系统平台的信息(显然,就像是我们在电脑上开了个虚拟机一样),当然,JVM执行字节码时实际上还是要解释成具体操作平台的机器指令的。

 

通过JVM,Java实现了平台无关性,Java语言在不同平台运行时不需要重新编译,只需要在该平台上部署JVM就可以了。因而能实现一次编译多处运行。(就像是你的虚拟机也可以在任何安了VMWare的系统上运行)

 

2. JRE和JDK

JRE:Java Runtime Environment,也就是JVM的运行平台,联系平时用的虚拟机,大概可以理解成JRE=虚拟机平台+虚拟机本体(JVM)。类似于你电脑上的VMWare+适用于VMWare的Ubuntu虚拟机。这样我们也就明白了JVM到底是个什么。

 

JDK:Java Develop Kit,Java的开发工具包,JDK本体也是Java程序,因此运行依赖于JRE,由于需要保持JDK的独立性与完整性,JDK的安装目录下通常也附有JRE。目前Oracle提供的Windows下的JDK安装工具会同时安装一个正常的JRE和隶属于JDK目录下的JRE。

 

3. JVM结构

JVM主要包括:程序计数器(Program Counter),Java堆(Heap),Java虚拟机栈(Stack),本地方法栈(Native Stack),方法区(Method Area)

 

详细的结构如下:

 

 

 

现在我来分别介绍一下每一部分的功能。

 

3.1. 程序计数器(PC, Program Counter)

是一个寄存器,可以看作是代码行号指示器,类似于实际计算机里的PC,用于指示,跳转下一条需要执行的命令。Java的基础操作以及异常处理等都十分依赖PC。

 

JVM多线程是通过线程轮流切换并分配处理器执行时间的方式来实现的。在一个确定的时刻,一个处理器(或者说多核处理器的一个内核)只会执行一条线程中的命令。因此,为了正常的切换线程,每个线程都会有一个独立的PC,各线程的PC不会互相影响。这个私有的PC所占的这块内存即是线程的“私有内存”。

 

如果线程在执行的是Java方法,那么PC记录的是正在执行的虚拟机字节码指令的地址。如果正在执行的不是Java方法即Native方法,那么PC的值为undefined。

 

PC的内存区域是唯一的没有规定任何OutOfMemoryError的Java虚拟机规范中的区域。

 

3.2. Java虚拟机栈(Stack,Java Virtual Mechine Stacks)

同PC一样(从工作流程图里我们可以看到,实际上,PC也是存在于JVM Stack上的),也是线程私有的,生命周期与线程相同。虚拟机栈描述Java方法执行的内存模型,每个方法被执行时都会创建一个栈帧(Stack Frame),栈帧会利用局部变量数组存储局部变量(Local Variables),操作栈(Operand Stack),方法出口(Return Value),动态连接(Current Class Constant Pool Reference)等信息。

 

局部变量数组存储了编译可知的八个基本类型(int, boolean, char, short, byte, long, float, double),对象引用(根据不同的虚拟机实现可能是引用地址的指针或者一个handle),returnAddress类型。64位的long和double会占用两个Slot,其余类型会占用一个Slot。在编译期间,局部变量所需的空间就会完成分配,动态运行期间不会改变所需的空间。

 

操作栈在执行字节码指令时会被用到,这种方式类似于原生的CPU寄存器,大部分JVM把时间花费在操作栈的花费上,操作栈和局部变量数组会频繁的交换数据。

 

动态连接控制着运行时常量池和栈帧的连接。所有方法和类的引用都会被当作符号的引用存在常量池中。符号引用是实际上并不指向物理内存地址的逻辑引用。JVM 可以选择符号引用解析的时机,一种是当类文件加载并校验通过后,这种解析方式被称为饥饿方式。另外一种是符号引用在第一次使用的时候被解析,这种解析方式称为惰性方式。无论如何 ,JVM 必须要在第一次使用符号引用时完成解析并抛出可能发生的解析错误。绑定是将对象域、方法、类的符号引用替换为直接引用的过程。绑定只会发生一次。一旦绑定,符号引用会被完全替换。如果一个类的符号引用还没有被解析,那么就会载入这个类。每个直接引用都被存储为相对于存储结构(与运行时变量或方法的位置相关联的)偏移量。

 

对Java虚拟机栈这个区域,Java虚拟机规范规定了两种异常:

 

线程请求的栈深度大于虚拟机所允许的深度,抛出StackOverFlow异常。

对于支持动态扩展的虚拟机,当扩展无法申请到足够的内存时会抛出OutOfMemory异常。

3.3. 本地方法栈(Native Stack)

本地方法栈如其名字,和Java Virtual Machine Stack其实极为类似,只是执行的是Native方法,为Native方法服务。在JVM规范中,没有对它的实现做具体规定。

 

3.4. Java 堆(Heap, Garbage Collection Heap)

 

 

Java堆是被所有线程共享的一块区域,在虚拟机启动时创建。此内存区域的唯一目的就是存放对象实例,几乎所有的对象实例都在这里分配内存(随着技术的发展,已不绝对)。

 

Java堆是垃圾收集器管理的主要区域,因而也被称为GC堆。收集器采用分代回收法,GC堆可以分为新生代(Yong Generation)和老生代(Old Generation)。新生代包括Eden Space和Survivor Space。但无论哪个区域,如何划分,存储的都是Java对象实例,进一步的划分是为了更好的回收内存或快速的分配内存。

 

根据Java虚拟机规范,堆所在的物理内存区间可以是不连续的,只要逻辑连续就可以。实现时既可以是固定大小,也可以是可扩展的。如果堆无法扩展时,就会抛出OutOfMemoryError。

 

3.5. 方法区(Method Area)

方法区和Java堆类似,也属于各线程共享的内存区域。用于存储已被虚拟机加载的类信息,常量,静态变量,即时编译器编译后的代码数据等。它属于非堆区(Non Heap),和Java堆区分开。对于存在永久代(Permanent)概念的虚拟机(HotSpot)而言,方法区存在于永久代。Java虚拟机规范对方法区的规定很宽松,甚至可以不实现GC。不过并非进入方法区的数据就会永久存在了,这块区域的内存回收主要为常量池的回收和类型的卸载。这个区域的回收处理不善也会导致严重的内存泄漏。

 

当方法区无法满足内存分配需求时也会抛出OutOfMemoryError。

 

3.6. 代码缓存(Code Cache)

用于编译和存储那些被 JIT 编译器编译成原生代码的方法。

 

3.7. 类信息(Class Data)

类信息存储在方法区,其主要构成为运行时常量池(Run-Time Constant Pool)和方法(Method Code)。

 

一个编译后的类文件包括以下结构:

 

结构 解释

magic, minor_version, major_version 类文件的版本信息和用于编译这个类的 JDK 版本。

constant_pool 类似于符号表,尽管它包含更多数据。下面有更多的详细描述。

access_flags 提供这个类的描述符列表。

this_class 提供这个类全名的常量池(constant_pool)索引,比如org/jamesdbloom/foo/Bar。

super_class 提供这个类的父类符号引用的常量池索引。

interfaces 指向常量池的索引数组,提供那些被实现的接口的符号引用。

fields 提供每个字段完整描述的常量池索引数组。

methods 指向constant_pool的索引数组,用于表示每个方法签名的完整描述。如果这个方法不是抽象方法也不是 native 方法,那么就会显示这个函数的字节码。

attributes 不同值的数组,表示这个类的附加信息,包括 RetentionPolicy.CLASS 和 RetentionPolicy.RUNTIME 注解。

3.8. 运行时常量池(Run-Time Constant Pool)

运行时常量池是方法区的一部分。Class文件中有类的版本,字段,方法,接口等描述信息和用于存放编译期生成的各种字面量和符号引用。这部分内容将在类加载后存放到方法区的运行时常量池中。Java虚拟机规范对Class的细节有着严苛的要求而对运行时常量池的实现不做要求。一般来说除了翻译的Class,翻译出来的直接引用也会存在运行时常量池中。

 

运行时常量池具备动态性,即运行时也可将新的常量放入池中。比如String类的intern()方法。

 

常量池无法申请到足够的内存分配时也会抛出OutOfMemoryError。

 

3.9. 直接内存(Direct Memory)

直接内存并不在Java虚拟机规范中,不是Java的一部分,但是也被频繁使用并可能导致OutOfMemoryError。Native函数库可以直接分配堆外内存,通过存储在Java堆里的DirectDataBuffer对象作为这块内存的引用进行操作。这样做在一些场景中可以显著提高性能。

 

直接内存是堆外内存,自然不受Java堆大小的限制,但是可能受实体机内存大小的限制。如果内存各部分总和大于实体机的内存时,也会报出OutOfMemoryError。

 

4. Java垃圾回收

将内存中不再被使用的对象进行回收,GC中用于回收的方法称为收集器,由于GC需要消耗一些资源和时间,Java在对对象的生命周期特征进行分析后,按照新生代、旧生代的方式来对对象进行收集,以尽可能的缩短GC对应用造成的暂停。

 

不同的对象引用类型, GC会采用不同的方法进行回收,JVM对象的引用分为了四种类型:

 

强引用:默认情况下,对象采用的均为强引用(这个对象的实例没有其他对象引用,GC时才会被回收)。

软引用:软引用是Java中提供的一种比较适合于缓存场景的应用(只有在内存不够用的情况下才会被GC)。

弱引用:在GC时一定会被GC回收。

虚引用:由于虚引用只是用来得知对象是否被GC。

5. JVM线程与原生线程的关系

JVM允许一个程序使用多个并发线程,Hotspot JVM中Java的线程与原生操作系统的线程是直接映射关系。即当线程本地存储、缓冲区分配、同步对象、栈、程序计数器等准备好以后,就会创建一个操作系统原生线程。Java 线程结束,原生线程随之被回收。操作系统负责调度所有线程,并把它们分配到任何可用的 CPU 上。当原生线程初始化完毕,就会调用 Java 线程的 run() 方法。run() 返回时,被处理未捕获异常,原生线程将确认由于它的结束是否要终止 JVM 进程(比如这个线程是最后一个非守护线程)。当线程结束时,会释放原生线程和 Java 线程的所有资源。

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

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

相关文章

js (一)数据类型与判断

数据类型 基本(值)类型: String 字符串是不可变的 let lang“java”; lang lang “script”; //先销毁再创建 Number 在数值类型中,存在一个特殊数值NaN,意为“不是数值”,用于表示本来要返回数值的…

计算机网络——计算机网络体系结构

文章目录 **1 计算机网络概述****1.1 概念****1.2 组成****1.3 功能****1.4 分类****1.5 性能指标** **2 计算机网络体系结构与参考模型****2.1 计算机网络分层结构****2.2 计算机网络协议,接口,服务的概念****2.3 ISO/OSI参考模型和TCP/IP模型** 1 计算…

操作系统Linux-day02

Linux学习 常见的cmd命令 winR 输入cmd打开窗口 ipconfig 查看ip地址信息ping查看网络连接情况或者网速情况 ping内网,外网,路由cd change directory 切换目录 cd 目录名称 切换到目录下 cd .. 切换到上一级 cd / 切换到根目录 dir 显示目录中的文…

Oracle初级

目录 概念 数据库分类 Oracle 存储结构 安装成功 ​编辑 创建用户和表空间 以超级管理员身份登录 创建表空间 创建用户 给用户授权 查询测试 概念 数据库(database): 物理操作系统文件或磁盘的集合。简单来说数据库的意思是数据的集合。 DBM…

基于51单片机的智能照明控制系统

**功能:**基于51单片机的智能照明控制系统,以51系列单片机为核心,使用光敏传感模块(采用ADC0832对光敏电路进行AD转换)、红外传感模块与声敏传感模块组成检测装置,并采用PWM对照明灯的光强度进行控制。 1.本设计分为手动模式和自动…

Python入门自学进阶-Web框架——37、异步IO与scrapy

异步IO: 一个请求多个网址并获取返回值的程序: import requestsurl_list [https://www.baidu.com,https://www.google.com,https://www.bing.com,https://www.sohu.com, ] for url in url_list:print(开始请求:,url)response requests.ge…

B068-项目实战-技术准备-Nosql-redis

目录 概述Redis简介:NoSql分类:Redis是什么特点(优势)Mysql、Memcached和Redis的比较使用场景 应用安装使用默认客户端redis-cli/命令行操作对value为string类型的常用操作对key的常用操作对list集合的常用操作其他命令行操作 jav…

JavaWeb(1)——HTML、CSS、JS 快速入门

JavaWeb 是使用 Java 技术来构建 Web 应用程序的一种方法。 HTML(超文本标记语言,负责网页的结构)是一种用于创建网页结构和内容的标记语言。它由一系列标签组成,每个标签都有特定的功能。开发人员可以使用 HTML 来定义页面的结构…

工作学习笔记

文章目录 一、java基础1、Hashcode的作用2、String、String StringBuffer 和 StringBuilder 的区别是什么?3、 Java的四种引用,强弱软虚4、3*0.1 0.3返回值是什么5、final修饰引用数据类型 二、jvm1、内存模型2、如何判断对象可以被回收3、Minor GC与Full GC分别在…

泊松比、泊松比范围、广义胡克定律、体积应变方程

泊松比(Poisson’s ratio)提供了有关不同材料在负载下如何变形的关键信息,将施加载荷的方向称为纵向(longitudinal direction),将垂直方向称为横向(lateral directions) 当在一个方…

RK3568平台开发系列讲解(编解码篇)编解码功能介绍及体验

🚀返回专栏总目录 文章目录 一、编解码功能简介二、音频和视频播放的操作2.1、使用 gplay 播放器播放视频和音频2.2、使用 gst-launch 播放视频2.3、使用 gst-launch 播放音频2.4、使用 gst-launch 播放视频和音频沉淀、分享、成长,让自己和他人都能有所收获!😄 📢本篇…

优化SQL查询实现高效数据检索(二)

大家好,本文将接着上文,继续介绍SQL查询优化的重要性以及如何优化SQL查询以实现更快的数据检索。 适当使用通配符 适当使用通配符对于优化SQL查询尤为重要,特别是在匹配字符串和模式方面。通配符是用于SQL查询中查找特定模式的特殊字符&…

【学生系统】基于结构体的一个训练小项目

(꒪ꇴ꒪ ),hello我是祐言博客主页:C语言基础,Linux基础,软件配置领域博主🌍快上🚘,一起学习!送给读者的一句鸡汤🤔:集中起来的意志可以击穿顽石!作者水平很有限,如果发现错误&#x…

Go []uint8和string的爱恨情仇

先上代码: package mainimport "fmt"func main() {byteSlice : []uint8{52, 44, 51} // 示例字节切片str : string(byteSlice)fmt.Printf("byteSlice:%v\r\n", str) }// 执行-输出 byteSlice:4,3 干货: 在Go语言中,[]u…

TiDB-学习笔记02

编写这个笔记,希望能记录下学习TiDB时候的知识点。 参考文章 目的链接&详细TiDB中文手册 Overview 面板重要监控指标详解 | PingCAP 文档中心 第二章 章节Overview 面板重要监控指标详解 | PingCAP 文档中心 认识Grafana Grafana监控TiDB 对应中文手册的【14…

如何使用 Java 代理插件在不更改应用程序代码的情况下捕获自定义指标

作者:Jack Shirazi Elastic APM Java 代理会自动跟踪许多指标,包括通过 Micrometer 或 OpenTelemetry Metrics API 生成的指标。 因此,如果你的应用程序(或其包含的库)已公开来自这些 API 之一的指标,则安装…

3Ds max无需插件创建逼真的草地

推荐: NSDT场景编辑器助你快速搭建可二次开发的3D应用场景 最终图像: 步骤-1 创建一个宽度 x 高度为 100100(我使用厘米)和 100100 段的平面。 步骤-2 将平面转换为“编辑多边形”并选择所有顶点(Ctrl A&#xff09…

AI Chat 设计模式:6. 装饰模式

本文是该系列的第六篇,内容采用问答式的方式展开,问题由我提出,答案由 Chat AI 作出,灰色背景的文字则主要是我的旁白。 问题列表 Q.1 你知道装饰模式吗A.1Q.2 详细说说装饰模式的组成角色A.2Q.3 举一个装饰模式的例子吧&#xf…

Threejs加载倾斜摄影OSGB数据

个人主页: 左本Web3D,更多案例预览请点击》 在线案例 个人简介:专注Web3D使用ThreeJS实现3D效果技巧和学习案例 💕 💕积跬步以至千里,致敬每个爱学习的你。获取模型或源码请点赞收藏加留言,有问…

数据库锁的12连问,抗住!

前言 金三银四很快就要来啦,准备了数据库锁的12连问,相信大家看完肯定会有帮助的。 1. 为什么需要加锁 在日常生活中,如果你心情不好想静静,不想被比别人打扰,你就可以把自己关进房间里,并且反锁。这就是生…