广西建设局网站首页,南宁网络推广平台,美容院网站建设,微信怎么关闭小程序功能Java虚拟机#xff08;JVM#xff09;架构和Java字节码101的初学者速成班 Java应用程序无处不在#xff0c;它们在我们的手机#xff0c;平板电脑和计算机上。 在许多编程语言中#xff0c;这意味着要多次编译代码才能使其在不同的OS上运行。 对于作为开发人员的我们来说… Java虚拟机JVM架构和Java字节码101的初学者速成班 Java应用程序无处不在它们在我们的手机平板电脑和计算机上。 在许多编程语言中这意味着要多次编译代码才能使其在不同的OS上运行。 对于作为开发人员的我们来说关于Java的最酷的事情可能是Java的设计与平台无关俗话说“写一次在任何地方运行”因此我们只需要编写和编译一次代码。 这怎么可能 让我们深入研究Java虚拟机JVM进行查找。 JVM架构 这听起来可能令人惊讶但是JVM本身对Java编程语言一无所知。 相反它知道如何执行自己的称为Java字节码的指令集该指令集以二进制类文件形式组织。 Java代码由javac命令编译为Java字节码然后由JVM在运行时将其翻译成机器指令。 线程数 Java被设计为并发的这意味着可以通过在同一进程中运行多个线程来同时执行不同的计算。 当新的JVM进程启动时将在JVM中创建一个新线程称为main thread 。 从该主线程开始运行代码并可以生成其他线程。 实际的应用程序可以具有成千上万个运行线程这些线程可以满足不同的目的。 有些服务于用户请求另一些则执行异步后端任务等等。 堆栈和框架 每个Java线程都会与框架堆栈一起创建该框架堆栈用于保存方法框架并控制方法的调用和返回。 方法框架用于存储数据及其所属方法的部分计算。 方法返回时其框架将被丢弃。 然后将其返回值传递回调用程序框架现在可以使用它来完成自己的计算。 JVM流程结构 用于执行方法的JVM游乐场是方法框架。 框架包括两个主要部分 局部变量数组 –存储方法的参数和局部变量的位置 操作数堆栈 –执行方法的计算的位置 框架结构 几乎每个字节码命令都会操纵这两个命令中的至少一个。 让我们看看如何。 怎么运行的 让我们来看一个简单的示例以了解不同元素如何一起运行以运行我们的程序。 假设我们有一个简单的程序来计算2 3的值并打印结果 class SimpleExample {public static void main(String[] args) {int result add(2,3);System.out.println(result);}public static int add(int a, int b) {return ab;}
} 要编译此类我们运行javac SimpleExample.java 生成编译文件SimpleExample.class 。 我们已经知道这是一个包含字节码的二进制文件。 那么我们如何检查类字节码呢 使用javap 。 javap是JDK附带的命令行工具可以反汇编类文件。 调用javap -c -p会打印出该类的反汇编字节码-c包括私有-p成员和方法 Compiled from SimpleExample.java
class SimpleExample {SimpleExample();Code:0: aload_01: invokespecial #1 // Method java/lang/Object.:()V4: returnpublic static void main(java.lang.String[]);Code:0: iconst_21: iconst_32: invokestatic #2 // Method add:(II)I5: istore_16: getstatic #3 // Field java/lang/System.out:Ljava/io/PrintStream;9: iload_110: invokevirtual #4 // Method java/io/PrintStream.println:(I)V13: returnpublic static int add(int, int);Code:0: iload_01: iload_12: iadd3: ireturn
} 现在JVM在运行时会发生什么 java SimpleExample启动一个新的JVM进程并创建了主线程。 为main方法创建一个新框架并将其推入线程堆栈。 public static void main(java.lang.String[]);Code:0: iconst_21: iconst_32: invokestatic #2 // Method add:(II)I5: istore_16: getstatic #3 // Field java/lang/System.out:Ljava/io/PrintStream;9: iload_110: invokevirtual #4 // Method java/io/PrintStream.println:(I)V13: return main方法具有两个变量 args和result 。 两者都驻留在局部变量表中。 main的前两个字节码命令iconst_2和iconst_3将常量值2和3分别加载到操作数堆栈中。 下一个命令invokestatic调用静态方法add。 由于此方法期望将两个整数用作参数因此invokestatic从操作数堆栈中弹出两个元素并将它们传递给JVM为add添加的新帧。 此时主操作数堆栈为空。 public static int add(int, int);Code:0: iload_01: iload_12: iadd3: ireturn 在添加框架中这些参数存储在局部变量数组中。 前两个字节码命令iload_0和iload_1将第0个和第1个局部变量加载到堆栈中。 接下来 iadd从操作数堆栈中弹出顶部的两个元素对其求和然后将结果推回堆栈中。 最后 ireturn弹出顶部元素并将其作为方法的返回值传递给调用框架并丢弃该框架。 public static void main(java.lang.String[]);Code:0: iconst_21: iconst_32: invokestatic #2 // Method add:(II)I5: istore_16: getstatic #3 // Field java/lang/System.out:Ljava/io/PrintStream;9: iload_110: invokevirtual #4 // Method java/io/PrintStream.println:(I)V13: return main的堆栈现在保存add的返回值。 istore_1弹出它并将其设置为索引1处的变量的值即result 。 getstatic将类型为java / io / PrintStream的静态字段java / lang / System.out推入堆栈。 iload_1将索引1处的变量现在等于5的结果值压入堆栈。 因此此时堆栈拥有2个值“ out”字段和值5。现在invokevirtual将要调用PrintStream.println方法。 它从堆栈中弹出两个元素第一个是对将要调用println方法的对象的引用。 第二个元素是要传递给println方法的整数参数该参数需要一个参数。 这是main方法打印add结果的地方。 最后 返回命令完成该方法。 主机被丢弃JVM进程结束。 就是这个。 总而言之不太复杂。 “一次编写随处运行” 那么什么使Java与平台无关 全部都在字节码中。 如我们所见任何Java程序都可以编译为标准Java字节码。 然后JVM在运行时将其转换为特定的机器指令。 我们不再需要确保我们的代码与机器兼容。 相反我们的应用程序可以在装有JVM的任何设备上运行并且JVM将为我们完成此操作。 JVM维护人员的工作是提供不同版本的JVM以支持不同的机器和操作系统。 这种体系结构使任何Java程序都可以在安装了JVM的任何设备上运行。 这样魔术就发生了。 最后的想法 Java开发人员可以在不了解JVM如何工作的情况下编写出色的应用程序。 但是深入研究JVM体系结构学习其结构并了解其如何解释代码将有助于您成为更好的开发人员。 它还将帮助您不时解决非常复杂的问题 PS。 如果您想更深入地研究JVM以及所有这些与Java异常的关系那就别无所求 这里可以。 翻译自: https://www.javacodegeeks.com/2018/05/jvm-architecture-101-get-to-know-your-virtual-machine.html