JVM相关特性

news2024/10/7 13:19:42

91865377d5ed4517948ebfbb7a933c62.jpg每个使用Java的开发者都知道Java字节码是在JRE中运行(JRE: Java 运行时环境)。JVM则是JRE中的核心组成部分,承担分析和执行Java字节码的工作,而Java程序员通常并不需要深入了解JVM运行情况就可以开发出大型应用和类库。尽管如此,如果你对JVM有足够了解,就会对Java有更好的掌握,并且能解决一些看起来简单但又尚未解决的问题。

 

 

所以,在本篇文章中,我将会介绍JVM工作原理,内部结构,Java字节码的执行及指令的执行顺序,并会介绍一些常见的JVM错误及其解决方案。最后会简单介绍下Java SE7带来的新特性。

 

虚拟机

JRE由Java API和JVM组成,JVM通过类加载器(Class Loader)加类Java应用,并通过Java API进行执行。

 

虚拟机(VM: Virtual Machine)是通过软件模拟物理机器执行程序的执行器。最初Java语言被设计为基于虚拟机器在而非物理机器,重而实现WORA(一次编写,到处运行)的目的,尽管这个目标几乎被世人所遗忘。所以,JVM可以在所有的硬件环境上执行Java字节码而无须调整Java的执行模式。

 

JVM的基本特性:

 

基于栈(Stack-based)的虚拟机: 不同于Intel x86和ARM等比较流行的计算机处理器都是基于寄存器(register)架构,JVM是基于栈执行的。

符号引用(Symbolic reference): 除基本类型外的所有Java类型(类和接口)都是通过符号引用取得关联的,而非显式的基于内存地址的引用。

垃圾回收机制: 类的实例通过用户代码进行显式创建,但却通过垃圾回收机制自动销毁。

通过明确清晰基本类型确保平台无关性: 像C/C++等传统编程语言对于int类型数据在同平台上会有不同的字节长度。JVM却通过明确的定义基本类型的字节长度来维持代码的平台兼容性,从而做到平台无关。

网络字节序(Network byte order): Java class文件的二进制表示使用的是基于网络的字节序(network byte order)。为了在使用小端(little endian)的Intel x86平台和在使用了大端(big endian)的RISC系列平台之间保持平台无关,必须要定义一个固定的字节序。JVM选择了网络传输协议中使用的网络字节序,即基于大端(big endian)的字节序。

Sun 公司开发了Java语言,但任何人都可以在遵循JVM规范的前提下开发和提供JVM实现。所以目前业界有多种不同的JVM实现,包括Oracle Hostpot JVM和IBM JVM。Google公司使用的Dalvik VM也是一种JVM实现,尽管其并未完全遵循JVM规范。与基于栈机制的Java 虚拟机不同的是Dalvik VM是基于寄存器的,Java 字节码也被转换为Dalvik VM使用的寄存器指令集。

 

Java 字节码

JVM使用Java字节码—一种运行于Java(用户语言)和机器语言的中间语言,以达到WORA的目的。Java字节码是部署Java程序的最小单元。

 

在介绍Java 字节码之前,我们先来看一下什么是字节码。下面涉及的案例是曾在一个真实的开发场景中遇到过的情境。

 

现象

一个曾运行完好的程序在更新了类库后却不能再次运行,并抛出了如下异常:

 

1 Exception in thread "main" java.lang.NoSuchMethodError: com.nhn.user.UserAdmin.addUser(Ljava/lang/String;)V

2 at com.nhn.service.UserService.add(UserService.java:14)

3 at com.nhn.service.UserService.main(UserService.java:19)

程序代码如下,并在更新类库之前未曾对这段代码做过变更:

 

1 // UserService.java

2 …

3 public void add(String userName) {

4 admin.addUser(userName);

5 }

类库中更新过的代码前后对比如下:

 

复制代码

 1 // UserAdmin.java - Updated library source code

 2 …

 3 public User addUser(String userName) {

 4 User user = new User(userName);

 5 User prevUser = userMap.put(userName, user);

 6 return prevUser;

 7 }

 8 // UserAdmin.java - Original library source code

 9 …

10 public void addUser(String userName) {

11 User user = new User(userName);

12 userMap.put(userName, user);

13 }

复制代码

简单来说就是addUser()方法在更新之后返回void而在更新之后返回了User类型实例。而程序代码因为不关心addUser的返回值,所以在使用的过程中并未做过改变。

 

初看起来,com.mhn.user.UserAdmin.addUser()依然存在,但为什么会出现NoSuchMethodError?

 

问题分析

主要原因是程序代码在更新类库时并未重新编译代码,也就是说,虽然程序代码看起来依然是在调用addUser方法而不关心其返回值,而对编译的类文件来说,他是要明确知道调用方法的返回值类型的。

 

可以通过下面的异常信息说明这一点:

 

 java.lang.NoSuchMethodError: com.nhn.user.UserAdmin.addUser(Ljava/langString;)V 

NoSuchMethodError 是因为"com.nhn.user.UserAdmin.addUser(Ljava/lang/String;)V"方法找不到引起的。看一下"Ljava/lang/String;"和后面的"V"。在Java字节码表示中,"L;"表示类的实例。所以上面的addUser方法需要一个java/lang/String对象作为参数。就这个案例中,类库中的addUser()方法的参数未发生变化,所以参数是正常的。再看一下异常信息中最后面的"V",它表示方法的返回值类型。在Java字节码表示中,"V"意味着该方法没有返回值。所以上面的异常信息就是说需要一个java.lang.String参数且没有任何返回值的com.nhn.user.UserAdmin.addUser方法找不到。

 

因为程序代码是使用之前版本的类库进编译的,class文件中定义的是应该调用返回"V"类型的方法。然而,在改变类库后,返回"V"类型的方法已不存在,取而代之的是返回类型为"Lcom/nhn/user/User;"的方法。所以便发生了上面看到的NoSuchMethodError。

 

注释

 

因为开发者未针对新类库重新编译程序代码,所以发生了错误。尽管如此,类库提供者却也要为此负责。因为之前没有返回值的addUser()方法既然是public方法,但后面却改成了会返回user实现,这意味着方法签名发生了明显的变化。这意味了该类库不能对之前的版本进行兼容,所以类库提供者必须事前对此进行通知。

 

我们重新回到Java 字节码,Java 字节码是JVM的基本元素,JVM本身就是一个用于执行Java字节码的执行器。Java编译器并不会把像C/C++那样把高级语言转为机器语言(CPU执行指令),而是把开发者能理解的Java语言转为JVM理解的Java字节码。因为Java字节码是平台无关的,所以它可以在安装了JVM(准确的说,是JRE环境)的任何硬件环境执行,即使它们的CPU和操作系统各不相同(所以在Windows PC机上开发和编译的class文件在不做任何调整的情况下就可以在Linux机器上执行)。编译后文件的大小与源文件大小基本一致,所以比较容易通过网络传输和执行Java字节码。

 

Java class文件本身是基于二进制的文件,所以我们很难直观的理解其中的指令。为了管理这些class 文件, JVM提供了javap命令来对二进制文件进行反编译。执行javap得到的是直观的java指令序列。在上面的案例中,通过对程序代码执行javap -c就可得到应用中的UserService.add()方法的指令序列,如下:

 

复制代码

1 public void add(java.lang.String);

2 Code:

3 0: aload_0

4 1: getfield #15; //Field admin:Lcom/nhn/user/UserAdmin;

5 4: aload_1

6 5: invokevirtual #23; //Method com/nhn/user/UserAdmin.addUser:(Ljava/lang/String;)V

7 8: return

复制代码

在上面的Java指令中,addUser()方法是在第五行被调用,即"5: invokevirtual #23"。这句的意思是索引位置为23的方法会被调用,方法的索引位置是由javap程序标注的。invokevirtual是Java 字节码中最常用到的一个操作码,用于调用一个方法。另外,在Java字节码中有4个表示调用方法的操作码: invokeinterface, invokespecial, invokestatic, invokevirtual 。他们每个的含义如下:

 

invokeinterface: 调用接口方法

invokespecial: 调用初始化方法、私有方法、或父类中定义的方法

invokestatic: 调用静态方法

invokevirtual: 调用实例方法

Java 字节码的指令集包含操作码(OpCode)和操作数(Operand)。像invokevirtual这样的操作码需要一个2字节长度的操作数。

 

对上面案例中的程序代码,如果在更新类库后重新编译程序代码,然后我们再反编译字节码将看到如下结果:

 

复制代码

1 public void add(java.lang.String);

2 Code:

3 0: aload_0

4 1: getfield #15; //Field admin:Lcom/nhn/user/UserAdmin;

5 4: aload_1

6 5: invokevirtual #23; //Method com/nhn/user/UserAdmin.addUser:(Ljava/lang/String;)Lcom/nhn/user/User;

7 8: pop

8 9: return

复制代码

如上我们看到#23对应的方法变成了具有返回值类型"Lcom/nhn/user/User;"的方法。

 

在上面的反编译结果中,代码前面的数字是具有什么含义?

 

它是一个一字节数字,也许正因此JVM执行的代码被称为“字节码”。像 aload0, getfield_ 和 invokevirtual 都被表示为一个单字节数字。(aload_0 = 0x2a, getfiled = 0xb4, invokevirtual = 0xb6)。因此Java字节码表示的最大指令码为256。

 

像aload0和aload1这样的操作码不需要任何操作数,因此aload_0的下一个字节就是下一个指令的

 

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

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

相关文章

008:vue中el-upload不显示上传的文件列表

第008个 查看专栏目录: VUE — element UI echarts,openlayers,cesium,leaflet,mapbox,d3,canvas 免费交流社区 专栏目标 在vue和element UI联合技术栈的操控下,本专栏提供行之有效的源代码示例…

废柴日记8:从入门到入狱的Python爬虫学习笔记1(入门篇)

前言:我错了,但下次也不一定(●’◡’●) 米娜桑,好久不见,不知道这段时间各位手中的西瓜刀有没有按时擦亮呢? 我也是在摸爬滚打将近一年之后总算是找到了一点人生的方向所以当成救命稻草现在正死死握紧不放手的啊。…

【Windows 系统笔记】使用服务器运行装载AList+本地安装RaiDrive进行网盘本地挂载

文章目录 前言准备工作一、购买一台云服务器配置服务器安装宝塔面板新建网站进入当前目录 二、安装AList三、登录四、开启域名访问五、挂载阿里云盘刷新令牌 六、使用RaiDrive挂载到本地 前言 大家肯定很好奇我为什么要写一篇这样的文章,因为之前一直使用本地挂载网…

SQL索引

一、索引概述 介绍: 索引是帮助MySQL高效获取数据的数据结构(有序)。在数据之外,数据库系统还维护着满足特定查找算法的数据结构,这些数据结构以某种方式引用(指向)数据,这样就可以…

【数据结构与算法】04 哈希表 / 散列表 (哈希函数、哈希冲突、链地址法、开放地址法、SHA256)

一种很好用,很高效,又一学就会的数据结构,你确定不看看? 一、哈希表 Hash Table1.1 核心概念1.2 哈希函数 Hash Function1.3 哈希冲突 Hash Collision1.4 哈希冲突解决1.41 方法概述1.42 链地址法 Separate Chaining1.43 开放寻址…

几种技巧让大模型(ChatGPT、文心一言)帮你提高写代码效率!

代码神器 自从大模型推出来之后,似乎没有什么工作是大模型不能做的。特别是在文本生成、文案写作、代码提示、代码生成、代码改错等方面都表现出不错的能力。下面我将介绍运用大模型写代码的几种方式,帮助程序员写出更好的代码!(…

华为OD机试真题 JavaScript 实现【一种字符串压缩表示的解压】【2022Q4 100分】,附详细解题思路

一、题目描述 有一种简易压缩算法:针对全部由小写英文字母组成的字符串,将其中连续超过两个相同字母的部分压缩为连续个数加该字母,其他部分保持原样不变。例如:字符串“aaabbccccd”经过压缩成为字符串“3abb4cd”。 请您编写解…

shell脚本学习记录(重定向)

Shell 输入/输出重定向 大多数 UNIX 系统命令从你的终端接受输入并将所产生的输出发送回​​到您的终端。 输出重定向 重定向一般通过在命令间插入特定的符号来实现。特别的,这些符号的语法如下所示: command1 > file1 上面这个命令执行command1然后将输出的…

maven访问仓库的顺序

1.没有配置私服的情况下(大部分情况下) 如上图所示,maven是依次从本地仓库、中央仓库和第三方仓库获取依赖的,其实在maven中并不是以这三种类型区分的,在maven中只有两种仓库类型,本地仓库和远程仓库&#…

Systemverilog中的Driving Strength讲解

在systemverilog中,net用于对电路中连线进行建模,driving strength(驱动强度)可以让net变量值的建模更加精确。net变量拥有4态逻辑值(0,1,z,x),它的driving strength有(supply,strong,pull,weak,highz)。net的值由连接到net的driver源(驱动源…

【开源工具】使用Whisper将提取视频、语音的字幕

这里写目录标题 一、语音转字幕操作步骤1、下载安装包Assets\WhisperDesktop.zip[^2]2、加载模型2.1 下载模型2.1.1 进入Hugging Face[^3]的仓库2.1.2 选择需要下载的模型2.1.3 配置模型路径 3、语音转字幕4、实时语言转录功能 二、相关简介[^1]特点开发人员指南构建说明其他注…

模拟退火(SA)算法

目录 模拟退火算法 主要代码 Mutate Sphere 模拟退火算法 主要代码 repmat 重复数组副本 B repmat(A,n) 返回一个数组,该数组在其行维度和列维度包含 A 的 n 个副本。A 为矩阵时,B 大小为 size(A)*n。 unifrnd 生成连续统一的随机数 sort 对数组进行…

抖音百科词条创建在哪里?

抖音作为中国火爆的短视频平台,拥有相当庞大的用户群体,用户在抖音上创建百科词条就可以获得非常可观的曝光和展现,抖音百科词条是通过哪种方式创建的呢?想要创建一个抖音百科怎么做?接下来伯乐网络传媒就来给大家讲一…

Linux之进程信号(上)

文章目录 前言一、进程信号二、查看命令kill -l与信号解释man 7 signal1.kill -l2.man 7 signal 三、信号的产生1.按键ctrl cctrl zctrl \ 2.系统调用kill——向任意进程发送信号raise——进程给自己发送任意信号abort——进程给自己指定的信号(6号信号&#xff…

主流解压缩软件有哪些?这四款可以满足你的所有需求

作者:Insist-- 个人主页:insist--个人主页 作者会持续更新网络知识和python基础知识,期待你的关注 目录 第一款:bandizip(推荐) 第二款:7-zip 第三款:Nanazip 第四款&#xff1a…

Vue中如何进行表单自定义验证

Vue中如何进行表单自定义验证 在Vue应用中,表单验证是非常重要的一部分。Vue提供了一些内置的验证规则,比如required、min、max等。但是有时候我们需要对表单进行自定义验证,以满足特定的业务需求。本文将介绍如何在Vue中进行表单自定义验证…

第十章 数学相关

第十章 数学相关 第一节 集合 真题(2010-53)-数学相关-集合-画饼集能力-朴素逻辑 53.参加某国际学术研讨会的 60 名学者中,亚裔学者 31 人,博士 33 人,非亚裔学者中无博士学位的 4 人。根据上述陈述,参…

Java16:集合

一:Collecction接口 1.单列集合框架结构 》Collection接口:单列集合,用来存储一个一个的对象 》 List接口:存储有序的,可重复的数据---》动态数组,实现类:ArrayList,LinkedList,…

【深蓝学院】手写VIO第3章--基于优化的 IMU 与视觉信息融合--作业

0. 题目 1. T1 T1.1 绘制阻尼因子曲线 将尝试次数和lambda保存为csv,绘制成曲线如下图 iter, lambda 1, 0.002000 2, 0.008000 3, 0.064000 4, 1.024000 5, 32.768000 6, 2097.152000 7, 699.050667 8, 1398.101333 9, 5592.405333 10, 1864.135111 11, 1242.7567…

【书影观后感 十四】左晖-做难而正确的事

距离上一本完整读完的书《李自成》及据此而作的读后感【书影观后感 十三】甲申三百七十八年祭已经接近一年时间了,最近心血来潮读了李翔的访谈形式系列《详谈》的第一本《左晖-做难而正确的事》。 虽然这本薄薄的书只有171页,访谈的形式也看似比较随意…