Java虚拟机(JVM)的工作方式,别再说你不会

在Java中,整数是原始数据类型。每个原始数据类型都有唯一的指令,该指令告诉它如何对该类型的操作数进行操作。例如,lsub字节码用于执行长整数减法,fsub字节码用于执行浮点减法,dsub字节码用于执行长整数减法。因此,将两个整数压入堆栈,然后将它们视为单个长整数是非法的。但是,将64位长的整数压入堆栈并占用两个32位插槽是合法的。

Java程序中的每个方法都有一个与之关联的堆栈框架。的堆栈帧保存与三组数据的方法的状态:该方法的局部变量,所述方法的执行环境,并且该方法的操作数栈。尽管局部变量和执行环境数据集的大小总是在方法调用开始时固定的,但是操作数堆栈的大小会随着执行方法的字节码指令而改变。由于Java堆栈宽32位,因此不能保证64位数字是64位对齐的。

执行环境

所述执行环境保持堆栈作为数据集之内,并且是用来处理动态链接,正常方法返回,和异常产生。为了处理动态链接,执行环境包含对当前方法和当前类的方法和变量的符号引用。通过动态链接到符号表将这些符号调用转换为实际的方法调用。

只要方法正常完成,就会向调用方法返回一个值。执行环境通过恢复调用方的寄存器并增加调用方的程序计数器以跳过方法调用指令来处理正常的方法返回。然后在调用方法的执行环境中继续执行程序。

如果当前方法的执行正常完成,则将值返回给调用方法。当调用方法执行适合于返回类型的返回指令时,会发生这种情况。

如果调用方法执行了不适合返回类型的返回指令,则该方法将引发异常或错误。可能发生的错误包括动态链接失败(例如,找不到类文件)或运行时错误(例如,在数组范围之外的引用)。发生错误时,执行环境将生成异常。

垃圾收集堆

在Java运行时环境中运行的每个程序都分配有一个垃圾回收堆。因为类对象的实例是从此堆分配的,所以堆的另一个词是内存分配池。默认情况下,在大多数系统上,堆大小设置为1MB。

尽管在启动程序时将堆设置为特定大小,但是例如在分配新对象时,堆可能会增长。为了确保堆不会变得太大,Java虚拟机会自动释放或垃圾回收不再使用的对象。

Java执行自动垃圾收集作为后台线程。在Java运行时环境中运行的每个线程都有两个与之关联的堆栈:第一个堆栈用于Java代码;第二个堆栈用于Java代码。第二个用于C代码。这些堆栈使用的内存是从总系统内存池中提取的。每当新线程开始执行时,就会为Java代码和C代码分配最大的堆栈大小。默认情况下,在大多数系统上,Java代码堆栈的最大大小为400KB,而C代码堆栈的最大大小为128KB。

如果我们的系统有内存限制,我们可以强制Java执行更积极的清理,从而减少使用的内存总量。为此,请减小Java和C代码堆栈的最大大小。如果我们的系统有很多内存,我们可以强制Java执行不太积极的清理,从而减少后台处理量。为此,请增加Java和C代码堆栈的最大大小。

恒量池

堆中的每个类都有一个与之关联的常量池。因为常量不变,所以它们通常在编译时创建。常量池中的项目编码特定类中任何方法使用的所有名称。该类包含一个对存在多少个常量的计数,以及一个偏移量,该偏移量指定在类说明中特定的常量列表从何处开始。

与常量关联的所有信息均基于常量的类型遵循特定格式。例如,类级常量用于表示类或接口,并具有以下格式:

CONSTANT_Class_info {
    u1   tag;
    u2 name_index;
}

tag的值在哪里CONSTANT_Class,并且name_index提供string了类的名称。类名int[][][[I。类名Thread[][Ljava.lang.Thread;

方法领域

Java的方法区域类似于其他编程语言使用的运行时环境的已编译代码区域。它存储与已编译代码中的方法相关联的字节码指令,以及执行环境进行动态链接所需的符号表。与该方法相关联的任何调试信息或其他信息也都存储在此区域中。

字节码指令集

尽管程序员更喜欢以高级格式编写代码,但是我们的计算机无法直接执行此代码,这就是为什么我们必须先编译Java程序,然后才能运行它们。通常,编译后的代码可以是称为机器语言的机器可读格式,也可以是诸如汇编语言或Java字节码的中间级格式。

Java虚拟机使用的字节码指令类似于汇编程序指令。如果您曾经使用过Assembler,则知道为了效率起见,将指令集精简到了最少,并且使用一系列指令来完成诸如打印到屏幕之类的任务。例如,Java语言允许我们使用单行代码在屏幕上打印,例如:

System.out.println("Hello world!"); 

在编译时,Java编译器将单行打印语句转换为以下字节代码:

0 getstatic #6 <Field java.lang.System.out Ljava/io/PrintStream;>
3 ldc #1 <String "Hello world!">
5 invokevirtual #7 <Method java.io.PrintStream.println(Ljava/lang/String;)V>
8 return

JDK提供了一种用于检查字节码的工具,称为Java类文件反汇编程序。我们可以通过在命令行中键入javap来运行反汇编程序。

由于字节码指令的格式很低,因此我们的程序几乎以编译为机器语言的程序的速度执行。机器语言中的所有指令均由0和1的字节流表示。在低级语言中,0和1的字节流被适当的助记符(例如字节代码指令)代替isub。与汇编语言一样,字节码指令的基本格式为:

<operation>   <operands(s)> 

因此,字节码指令集中的一条指令由一个1字节的操作码(指定要执行的操作)以及零个或多个提供该操作将使用的参数或数据的操作数组成。

摘要

Java虚拟机仅存在于我们计算机的内存中。在我们计算机内存中复制一台机器需要七个关键对象:一组寄存器,一个堆栈,一个执行环境,一个垃圾收集堆,一个常量池,一个方法存储区以及一种将它们捆绑在一起的机制。该机制是字节码指令集。

要检查字节码,我们可以使用Java类文件反汇编程序javap。通过详细检查字节码指令,我们获得了有关Java虚拟机和Java本身内部工作的宝贵见解。每个字节代码指令执行范围非常有限的特定功能,例如将对象压入堆栈或将对象弹出堆栈。这些基本功能的组合代表了复杂的高级任务,这些任务定义为Java编程语言中的语句。看起来如此惊人,有时会使用数十个字节代码指令来执行单个Java语句指定的操作。当我们将这些字节码指令与虚拟机的七个关键对象一起使用时,Java获得了平台独立性,成为世界上功能最强大,用途最广泛的编程语言。

问题:Java类反编译,使用什么命令?

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值