1、JVM基础

1.1、JDK,JRE,JVM关系

JDK

  • JDK(Java Development Kit) 是用于开发 Java 应用程序的软件开发工具集合,包括 了 Java 运行时的环境(JRE)、解释器(Java)、编译器(javac)、Java 归档 (jar)、文档生成器(Javadoc)等工具。简单的说我们要开发Java程序,就需要安 装某个版本的JDK工具包。

JRE

  • JRE(Java Runtime Enviroment )提供 Java 应用程序执行时所需的环境,由 Java 虚拟机(JVM)、核心类、支持文件等组成。简单的说,我们要是想在某个机器上运 行Java程序,可以安装JDK,也可以只安装JRE,后者体积比较小。

JVM

  • Java Virtual Machine(Java 虚拟机)有三层含义,分别是: JVM规范要求 满足 JVM 规范要求的一种具体实现(一种计算机程序) 一个 JVM 运行实例,在命令提示符下编写 Java 命令以运行 Java 类时,都会创建一 个 JVM 实例,我们下面如果只记到JVM则指的是这个含义;如果我们带上了某种JVM 的名称,比如说是Zing JVM,则表示上面第二种含义

JDK 与 JRE、JVM 之间的关系
JDK > JRE > JVM

  • JDK = JRE + 开发工具
  • JRE = JVM + 类库

三者在开发运行Java程序时的交互关系: 简单的说,就是通过JDK开发的程序,编译以后,可以打包分发给其他装有JRE的机器上去运行 而运行的程序,则是通过java命令启动的一个JVM实例,代码逻辑的执行都运行在这个JVM实例上

Java程序的开发运行过程为: 我们利用 JDK (调用 Java API)开发Java程序,编译成字节码或者打包程序。然后可以用 JRE 则启动一个JVM实例,加载、验证、执行 Java 字节码以及依赖库,运行Java程序 而JVM 将程序和依赖库的Java字节码解析并变成本地代码执行,产生结果

2、Java字节码

2.1、定义

  • Java字节码是JVM的指令集
  • JVM加载字节码格式的class文件,检验之后通过JIT编译器转换为本地机器代码执行。
  • Java字节码就是JVM执行的指令格式

2.2、操作码

  • Java bytecode 由单字节( byte )的指令组成,理论上最多支持256 个操作码(opcode)。实际上Java只使用了200左右的操作码, 还有一些操作码则保留给调试操作。
  • 操作码, 下面称为 指令 , 主要由 类型前缀 和 操作名称 两部分组成。

2.3、指令性质

    1. 栈操作指令,包括与局部变量交互的指令
    1. 程序流程控制指令
    1. 对象操作指令,包括方法调用指令
    1. 算术运算以及类型转换指令

2.4、字节码的分类

  1. 栈操作指令,包括与局部变量交互的指令
  2. 程序流程控制指令
  3. 对象操作指令,包括方法调用指令
  4. 算术运算以及类型转换指令

2.5、字节码阅读

源码:

package com.zhz.bytecode;/*** @author zhouhengzhe* @Description: TODO* @date 2021/9/15下午7:57* @since*/public class HelloByteCode {public static void main(String[] args) {HelloByteCode helloByteCode=new HelloByteCode();System.out.println(helloByteCode);}
}

第一步先:

javac HelloByteCode.java    =》  会生成一个HelloByteCode.class
  • Javac 不指定 -d 参数编译后生成的 .class 文件默认和源代码在同一个目录。 注意: javac 工具默认开启了优化功能, 生成的字节码中没有局部变量表(LocalVariableTable),相当于 局部变量名称被擦除。如果需要这些调试信息, 在编译时请加上 -g 选项。
  • JDK自带工具的详细用法, 请使用: javac -help 或者 javap -help 来查看;

打开 HelloByteCode.class

cafe babe 0000 0034 001c 0a00 0600 0f07
0010 0a00 0200 0f09 0011 0012 0a00 1300
1407 0015 0100 063c 696e 6974 3e01 0003
2829 5601 0004 436f 6465 0100 0f4c 696e
654e 756d 6265 7254 6162 6c65 0100 046d
6169 6e01 0016 285b 4c6a 6176 612f 6c61
6e67 2f53 7472 696e 673b 2956 0100 0a53
6f75 7263 6546 696c 6501 0012 4865 6c6c
6f42 7974 6543 6f64 652e 6a61 7661 0c00
0700 0801 001e 636f 6d2f 7a68 7a2f 6279
7465 636f 6465 2f48 656c 6c6f 4279 7465
436f 6465 0700 160c 0017 0018 0700 190c
001a 001b 0100 106a 6176 612f 6c61 6e67
2f4f 626a 6563 7401 0010 6a61 7661 2f6c
616e 672f 5379 7374 656d 0100 036f 7574
0100 154c 6a61 7661 2f69 6f2f 5072 696e
7453 7472 6561 6d3b 0100 136a 6176 612f
696f 2f50 7269 6e74 5374 7265 616d 0100
0770 7269 6e74 6c6e 0100 1528 4c6a 6176
612f 6c61 6e67 2f4f 626a 6563 743b 2956
0021 0002 0006 0000 0000 0002 0001 0007
0008 0001 0009 0000 001d 0001 0001 0000
0005 2ab7 0001 b100 0000 0100 0a00 0000
0600 0100 0000 0a00 0900 0b00 0c00 0100
0900 0000 3000 0200 0200 0000 10bb 0002
59b7 0003 4cb2 0004 2bb6 0005 b100 0000
0100 0a00 0000 0e00 0300 0000 0c00 0800
0d00 0f00 0e00 0100 0d00 0000 0200 0e

javap -c -verbose HelloByteCode

Classfile /Users/mac/Documents/ideaproject/Java/Java基础/HelloByteCode.classLast modified 2021-9-15; size 447 bytesMD5 checksum 6631029ab59bc19003c854c3360c6a70Compiled from "HelloByteCode.java"
public class com.zhz.bytecode.HelloByteCodeminor version: 0major version: 52flags: ACC_PUBLIC, ACC_SUPER
Constant pool:#1 = Methodref          #6.#15         // java/lang/Object."<init>":()V#2 = Class              #16            // com/zhz/bytecode/HelloByteCode#3 = Methodref          #2.#15         // com/zhz/bytecode/HelloByteCode."<init>":()V#4 = Fieldref           #17.#18        // java/lang/System.out:Ljava/io/PrintStream;#5 = Methodref          #19.#20        // java/io/PrintStream.println:(Ljava/lang/Object;)V#6 = Class              #21            // java/lang/Object#7 = Utf8               <init>#8 = Utf8               ()V#9 = Utf8               Code#10 = Utf8               LineNumberTable#11 = Utf8               main#12 = Utf8               ([Ljava/lang/String;)V#13 = Utf8               SourceFile#14 = Utf8               HelloByteCode.java#15 = NameAndType        #7:#8          // "<init>":()V#16 = Utf8               com/zhz/bytecode/HelloByteCode#17 = Class              #22            // java/lang/System#18 = NameAndType        #23:#24        // out:Ljava/io/PrintStream;#19 = Class              #25            // java/io/PrintStream#20 = NameAndType        #26:#27        // println:(Ljava/lang/Object;)V#21 = Utf8               java/lang/Object#22 = Utf8               java/lang/System#23 = Utf8               out#24 = Utf8               Ljava/io/PrintStream;#25 = Utf8               java/io/PrintStream#26 = Utf8               println#27 = Utf8               (Ljava/lang/Object;)V
{public com.zhz.bytecode.HelloByteCode();descriptor: ()Vflags: ACC_PUBLICCode:stack=1, locals=1, args_size=10: aload_01: invokespecial #1                  // Method java/lang/Object."<init>":()V4: returnLineNumberTable:line 10: 0public static void main(java.lang.String[]);descriptor: ([Ljava/lang/String;)Vflags: ACC_PUBLIC, ACC_STATICCode:stack=2, locals=2, args_size=10: new           #2                  // class com/zhz/bytecode/HelloByteCode3: dup4: invokespecial #3                  // Method "<init>":()V7: astore_18: getstatic     #4                  // Field java/lang/System.out:Ljava/io/PrintStream;11: aload_112: invokevirtual #5                  // Method java/io/PrintStream.println:(Ljava/lang/Object;)V15: returnLineNumberTable:line 12: 0line 13: 8line 14: 15
}
SourceFile: "HelloByteCode.java"

上面的字节码详解

super():

无参构造函数的参数个数居然不是0: stack=1, locals=1,args_size=1 。 这是因为在 Java 中, 如果是静态方法则没有 this 引用。 对于非静态方法, this 将被分配到局部变量表的第0号槽位中

我们通过查看编译后的class文件证实了其中存在默认构造函数,所以这是Java编译器生成的, 而不是运行时JVM自动生成的。** 自动生成的构造函数,其方法体应该是空的**,但这里看到里面有一些指令。为什么呢? 再次回顾Java知识, 每个构造函数中都会先调用 super 类的构造函数对吧? 但这不是JVM自动执行的, 而是由程序指令控制,所以默认构造函数中也就有一些字节码指令来干这个事情。


java/lang/Object:

默认继承了 Object 类


main

可以看到方法描述: **([Ljava/lang/String;)V **:

  • 其中小括号内是入参信息/形参信息,
  • 左方括号表述数组,
  • L 表示对象,
  • 后面的 java/lang/String 就是类名称
  • 小括号后面的 V 则表示这个方法的返回值是 void
  • 方法的访问标志也很容易理解 **flags: ACC_PUBLIC, ACC_STATIC ,表示public和static **
  • 还可以看到执行该方法时需要的栈(stack)深度是多少,需要在局部变量表中保留多少个槽位, 还有方法的参 数个数: stack=2, locals=2, args_size=1 。把上面这些整合起来其实就是一个方法:
  • **public static void main(java.lang.String[]); **
  • 注:实际上我们一般把一个方法的修饰符+名称+参数类型清单+返回值类型,合在一起叫“方法签名”, 即这些信息可以完整的表示一个方法。
  • main 方法中创建了该类的一个实例, 然后就return了

常量池:

常量池 大家应该都听说过, 英文是 Constant pool 。这里做一个强调: 大多数时候指的是运行时常量池 。但运行时常量池里面的常量是从哪里来的呢? 主要就是由 class 文件中的常量池结构体组成的。

  • 其中显示了很多关于class文件信息: 编译时间, MD5校验和, 从哪个 .java 源文件编译得来,符合哪个版本的Java语言规范等等。
  • 还可以看到 ACC_PUBLICACC_SUPER 访问标志符。
  • ACC_PUBLIC 标志很容易理解:这个类是 public 类,因此用这个标志来表示。 但 ACC_SUPER 标志是怎么回事呢? 这就是历史原因, JDK1.0 的BUG修正中引入 ACC_SUPER 标志来修正 invokespecial 指令调用 super 类方法的问题,从 Java 1.1 开始, 编译器一般都会自动生成ACC_SUPER 标志。

解释 #1, #2, #3

#3=#2.#15=#16.#15=#16.#7:#8=com/zhz/bytecode/HelloByteCode.""

JVM(1)——字节码相关推荐

  1. JVM学习-字节码指令

    目录 1.入门 2 javap 工具 3 图解方法执行流程 3.1.原始 java 代码 3.2.编译后的字节码文件 3.3.常量池载入运行时常量池 3.4.方法字节码载入方法区 3.5.main 线 ...

  2. JVM与字节码——2进制流字节码解析

    为什么80%的码农都做不了架构师?>>>    字节码解析 结构 本位将详细介绍字节码的2进制结构和JVM解析2进制流的规范.规范对字节码有非常严格的结构要求,其结构可以用一个JSO ...

  3. jvm理论-字节码指令

    Java虚拟机的指令由一个字节长度的.代表着某种特定操作含义的数字(称为操作码,Opcode)以及跟随其后的零至多个代表此操作所需参数(称为操作数,Operands)而构成. 基本数据类型 1.除了l ...

  4. JVM Class字节码之三-使用BCEL改变类属性

    使用BCEL动态改变Class内容 之前对Class文件中的常量池,Method的字节码指令进行了说明. JVM Class详解之一 JVM Class详解之二 Method字节码指令 现在我们开始实 ...

  5. 【JVM】字节码与ASM字节码增强、Instrument实现类的动态重加载

    目录 字节码与ASM字节码增强 什么是字节码? 字节码结构 操作数栈与字节码 字节码增强 ASM 运行时类加载 Instrument JPDA与JVMTI instrument实现热加载的过程 字节码 ...

  6. 第六章JVM虚拟机字节码执行引擎——类文件和类加载之前必看

    文章目录 虚拟机字节码执行引擎 运行时栈帧结构 局部变量表(Local Variables) 操作数栈 动态链接(Dynamic Linking) 方法返回地址 附加信息 方法调用 解析 分派 虚方法 ...

  7. 深入理解JVM 一字节码详解

    今天继续总结JVM,计划本周完成这个系列的整理.总结. 本节内容枯燥,胆小者勿入! Write Once,Run Anywhere--byteCode byteCode 平台无关 java通过存储编译 ...

  8. 深入理解JVM一字节码执行

    文章目录 前言 栈帧结构 每个方法调用开始到退出,都对应着一个"栈帧"进站与出站. 运行时栈帧 栈帧-局部变量表 栈帧-操作数栈(Operand Stack) 栈帧-动态连接 栈帧 ...

  9. 欧尼酱讲JVM(08)——字节码中方法内部结构的剖析

    用到的工具--Jclasslib IDEA提供了插件,很方便. 首先 先看一段代码: public class LocalVariablesTest {private int count = 0;pu ...

最新文章

  1. python 帮助文档、自我解释
  2. 智能卡检测控制系统检测m1这么操作_土壤检测实验室仪器设备配置方案
  3. java mvp开发_如何从没有软件开发技能的想法变成现实的市场MVP?️?
  4. App后台开发运维和架构实践学习总结(8)——后台产品设计的4个原则
  5. 什么是DevSecOps?
  6. 互联网转型需要微服务架构
  7. 定时器编写   例子
  8. 以30字符宽居中输出python字符串_从零开始学 Python 之字符串
  9. 【零经验】游戏制作全流程攻略(Unity、个人开发、找工作)
  10. UWP—网易云音乐的APP分析
  11. matlab 曲线 标注,请问关于Matlab曲线标注问题
  12. Leetcode 2233. Maximum Product After K Increments
  13. 电子商务站点资源收集~~~
  14. 多线程与单线程的区别
  15. 2-10 CAD基础 偏移(offset)
  16. HTML5.笔记.案例
  17. Hadoop_day04学习笔记
  18. itextpdf text转pdf
  19. 我愿为这二极管奉献我的一生
  20. 2021-2027全球及中国光刻掩膜版行业研究及十四五规划分析报告

热门文章

  1. 云南大学计算机在职硕士,云南大学信息学院硕士研究生教育
  2. 单例模式(Singleton) 1
  3. 1.18 Spreadsheet
  4. Android多线程断点续传下载原理及实现,移动开发工程师简历
  5. Netty使用FileUpload报错Not represented by a file
  6. 快速破解专业操盘手核心机密(全套)
  7. 激励员工的书推荐:这5本书让你学会员工激励
  8. 用计算机进行会计核算与手工会计核算,会计核算软件与手工会计核算软件有什么区别...
  9. 微信公众号服务器端脑图,微信公众号中隐藏的思维导图工具,帮你随时随地高效思考...
  10. 【Flink】需求实现之独立访客数量的计算 和 布隆过滤器的原理及使用