way-to-architect
  • 前言
  • Java
    • Java关键字
      • Java中四种修饰符的限制范围
      • static和final
    • 容器
      • 容器概述
        • 容器:综述
        • Iterator原理及实现
        • fast-fail机制
        • 比较器Comparator
        • Collections工具类
      • List
        • List综述
        • ArrayList原理分析
        • ArrayList在循环过程中删除元素的问题
        • 常用的小技巧
        • CopyOnWrite
      • Set
        • Set综述
        • HashSet
        • LinkedHashSet
        • TreeSet
      • Queue
        • Queue综述
        • ArrayBlockingQueue实现原理
        • LinkedBlockingQueue实现原理
        • 高性能无锁队列Disruptor
      • Map
        • Map综述
        • HashMap
          • HashMap实现原理
          • HashMap中的位运算
          • HashMap其他问题
        • LinkedHashMap
        • TreeMap
        • ConcurrentHashMap
          • ConcurrentHashMap实现原理JDK1.7
          • ConcurrentHashMap实现原理JDK1.8
        • ConcurrentSkipListMap
        • Map中key和value的null的问题
    • 线程
      • 线程
        • 创建线程
        • 线程状态及切换
        • 线程中断的理解
        • 几种方法的解释
        • 用户线程与守护线程
        • 线程组ThreadGroup
      • 线程池
        • 线程池工作原理及创建
        • Executor
        • 如何确保同一属性的任务被同一线程执行
      • ThreadLocal
        • ThreadLocal原理
        • ThreadLocal之父子线程传值
        • InheritableThreadLocal
      • 同步与锁
        • 线程安全与锁优化
        • synchronize关键字
        • Lock
          • 队列同步器
            • 同步状态的获取与释放
            • 使用方式
            • 示例:Mutex
            • 示例:TwinsLock
          • 重入锁和读写锁
          • LockSupport
          • Condition
          • 并发工具类
        • CAS
          • CAS的理解
          • Java中原子操作类
        • 3个经典同步问题
      • fork/join的理解
    • I/O
      • I/O概述
        • 磁盘I/O与网络I/O
        • 主要接口
        • 输入流和输出流的使用示例
        • InputStream的重复读
        • BufferdxxxxStream
        • Serailizable
        • File常用方法
        • Files和Path
        • RandomAccessFile
        • 通过零拷贝实现有效数据传输
        • 正确地处理文件
      • NIO基础
      • NIO2
      • Netty
        • Java I/O的演进之路
        • 为什么是Netty
        • 更多
      • I/O调优
    • 异常
      • 异常体系及为什么要有这种异常设计
      • 多catch的执行情况
      • try catch finally 与reture
      • 异常处理的误区
      • Preconditions:方法入参校验工具
    • 枚举
      • 常见用法
      • 枚举类在序列化中的问题
    • 注解
      • 概述
      • Spring中的组合注解的条件注解
      • 常用注解
        • JSR-330标准注解
    • 反射
      • 概述
      • 内部类的反射
      • 反射中需要注意的地方
    • 流程控制
      • switch case without break
      • Java: for(;;) vs. while(true)
    • JVM
      • JVM内存结构
      • Java内存模型
      • 垃圾收集器和内存分配策略
      • 四种引用类型区别及何时回收
      • 类文件结构
      • 类初始化顺序
      • 类加载机制
      • 虚拟机执行引擎
      • 逃逸分析
      • JVM常用配置
      • GC日志分析
      • Java8 JVM 参数解读
      • 垃圾收集器和内存分配策略
    • 面向对象
      • Object类中的方法
      • Class类中的方法
      • 值传递还是引用传递?
      • 接口和抽象类的区别
      • 深拷贝和浅拷贝
      • Integer.parseInt()与Interger.valueof()
      • hashCode()与equal()
      • String
        • String池化及intern()方法的作用
        • 关于字符串
    • 序列化
      • Java序列化的方式有哪些?
    • 新特性
      • 流 Stream
        • Stream是什么
        • Stream API详解
        • Stream进阶
        • 流编程
        • 其他事项
      • lambda表达式
      • 默认方法(Default Methods)
      • @FunctionalInterface注解
    • SPI
      • 理解SPI
    • 字节码
      • javaagent
      • 字节码操纵
      • 如何查看类编译后的字节码指令
      • 字节码指令有哪些
  • Python
    • 异常处理
  • Go
  • 数据结构与算法
    • 数据结构
      • 概述
        • 线性表
        • 栈
        • 队列
        • 串
        • 树
        • 图
      • Java的一些实现
      • 红黑树
      • 双缓冲队列
      • 跳表SkipList
    • 算法
      • 概述
      • 常见算法
        • 基本排序
        • 高级排序
        • 动态规划
  • 框架或工具
    • Spring
      • Spring基础
        • Spring整体架构
        • 什么是IoC
        • Ioc容器的基本实现
        • Spring的MainClass
          • Spring的BeanFactory
          • Spring的Register
          • Spring的Resource和ResourceLoader
          • Spring的PropertySource
          • Spring的PropertyResolver
          • Spring的PropertyEditor
          • Spring的Convert
          • Spring的BeanDefinition
          • Spring的BeanDefinitionReader
          • Spring的BeanDefiniton其他Reader
          • Spring的BeanDefinition其他Reader2
          • Spring的Aware
          • Spring的BeanFctoryPostProcessor
          • Spring的BeanPostProcessor
          • Spring的Listener
        • Xml格式的应用启动
          • Xml格式的应用启动2
          • Xml格式的应用启动3
          • Xml格式的应用启动4
          • Xml格式的应用启动5
          • Xml格式的应用启动6
          • Xml格式的应用启动7
        • Spring中的设计模式
        • 什么是AOP
        • Spring中AOP的实现
      • Spring应用
        • Spring的事务控制
        • @Transactional注解在什么情况下会失效
        • 如何在数据库事务提交成功后进行异步操作
        • Spring中定时任务的原理
    • SpringMVC
      • Controller是如何将参数和前端传来的数据一一对应的
      • 请求处理流程
    • Zookeeper
      • Zookeeper是什么
      • Zookeeper能干啥
    • Shiro
    • druid
    • Netty
    • Consul
      • Consul是什么
    • etcd
    • confd
    • Akka
      • Actor模型是什么
  • 数据库
    • 基本概念
    • MySQL
      • 基本配置
      • MySQL数据类型
      • MySQL存储引擎
      • MySQL事务
        • MySQL事务概念
      • MySQL索引
        • MySQL中的索引类型
        • B-Tree/B+Tree概述
        • 为什么使用B+Tree
        • MySQL中的B+Tree索引
        • MySQL高性能索引策略
      • MySQL查询
        • MySQL查询过程
        • MySQL查询性能优化
        • 使用EXPLAIN
      • MySQL锁
        • MySQL中锁概述
        • InnoDB的并发控制
        • MySQL乐观锁
      • MySQL分库分表
        • 分库/分表
        • 跨库JOIN
        • 跨库分页
        • 分库分表后的平滑扩容
        • 分区表
        • 分布式ID生成方法
      • MySQL实战
        • 在线表结构变更
        • MySQL优化规则
        • MySQL问题排查
        • 常见查询场景
    • Redis
    • Hbase
    • OpenTSDB
    • rrd
    • MongoDB
    • 连接池
  • 系统设计
    • 一致性Hash算法
    • 限流
      • 限流是什么
      • 限流算法
      • 应用内限流
      • 分布式限流
      • 接入层限流
        • ngx_http_limit_conn_module
        • ngx_http_limit_req_module
        • lua_resty_limit-tarffic
      • 节流
    • 降级
      • 降级详解
      • 人工降级开关的实现
      • 自动降级的实现:Hystrix
    • 负载均衡
      • 概述
      • 互联网架构下的负载均衡
      • Nginx负载均衡(七层)
      • Nginx负载均衡(四层)
      • Nginx动态配置
    • 超时与重试机制
      • 什么地方要超时与重试
      • 代理层超时与重试
      • Web容器超时
      • 中间件客户端超时与重试
      • 数据库超时
      • NoSQL客户端超时设置
      • 业务超时
      • 前端请求超时
    • 网关
    • CAP
      • 什么是CAP
      • CAP理解
    • 生产者-消费者模型
      • 使用notify/wait方式
      • 使用await/signal实现
      • 使用阻塞队列实现
      • 使用信号量实现
      • 使用管道流实现
      • 无锁队列Disruptor
      • 双缓冲队列
    • 缓存
      • 缓存概述
      • 数据库缓存
      • 应用缓存
      • 前端缓存
      • 本地缓存
    • 秒杀
    • LRU
  • 版本控制
    • Git
      • Git常用命令
      • 场景命令
    • Svn
  • 计算机操作系统
    • Linux
      • Linux中重要概念
      • 常用命令
      • 查看日志
      • 权限管理
      • 登录或传输
      • 防火墙
      • 配置ssh免密
      • 进程
      • 防火墙
    • Mac
    • 计算机基础
      • 进制
      • Java中的位运算
      • 计算机存储系统结构
  • 网络
    • TCP三次握手和四次挥手
    • 网络术语
      • 网关、路由器、交换机、IP等
      • VLAN
      • LAN
  • 设计模式
    • 设计模式概述
    • 创建型
      • 单例模式
      • 工厂模式
      • 建造者模式
      • 原型模式
      • 享元模式
    • 行为型
      • 观察者模式
      • 策略模式
      • 模板模式
      • 责任链模式
      • 命令模式
      • 外观模式
      • 迭代器模式
      • 中介者模式
        • 中介模式续
      • 状态模式
        • 状态模式实例
        • 状态模式思考
      • 访问者模式
        • 访问者实例1
        • 访问者模式续
    • 结构型
      • 组合模式
        • 组合模式续
      • 装饰模式
        • 装饰模式续
      • 代理模式
      • 备忘录模式
      • 桥接模式
        • 桥接模式实例一
  • 构建工具
    • Maven
      • 常用命令
      • Maven生命周期
      • Maven中的变量和属性
      • 不同环境的如何配置不同的变量
      • 常用插件及配置
      • 其他问题
      • dependencies与dependencyManagement的区别
    • Gradle
  • 大数据
    • Hadoop
    • Storm
    • Spark
  • 服务器
    • Tomcat
      • server.xml配置详解
      • 线程池和连接数配置
      • Maven远程部署
      • 一些小技巧
      • Tomcat类加载机制分析
      • Tomcat的日志
      • Tomcat架构
        • 概述
        • Server 的启动流程
        • 请求处理流程
    • Nginx
      • 常用命令
      • 基本配置
      • Lua
    • Tengine
  • 中间件
    • 任务调度
      • 为什么需要任务调度
    • 消息队列
      • 为什么需要消息队列
      • 消息队列关键点
      • 消息中间件需要解决的问题
      • 不同消息队列产品对比
      • RocketMQ
        • 快速入门
        • 整体架构
        • 部署方式
          • Broker部署方案
        • 客户端使用
          • 客户端使用指南
          • 快速开始
          • 简单示例
          • 有序消息示例
          • 广播消息示例
          • 定时消息示例
          • 批量消息示例
          • 过滤消息示例
          • 日志输出配置示例
        • 关键点实现
          • 顺序消息的实现
        • 最佳实践
          • Broker的最佳实践
          • 生产者最佳实践
            • 生产者最佳实践续
          • 消费者最佳实践
            • 消费者最佳实践续
          • 名称服务最佳实践
          • JVM/kernel配置的最佳实践
          • 新特性 Filter Server
          • 其他事项
      • RabbitMQ
      • Kafka
    • 分布式事务
      • 什么是分布式事务
      • 解决方案
    • 服务治理
      • RPC概念
      • RPC最简实现
      • 为什么需要服务治理
      • Dubbo
        • Dubbo整体架构
      • Java RMI
    • 分布式锁
      • 如何设计分布式锁
        • 基于zookeeper
        • 基于Redis
    • 注册中心
      • 注册中心的职责
      • 不同注册中心的比较
    • 配置中心
      • 概述
      • 配置中心的实现与选型
  • Web开发
    • Http请求类型及区别
    • 常见的content-type
    • 如何处理跨域
    • Restful最佳实践
    • HTTP状态码
    • Http下载原理
  • 测试
    • 压测:apache bench
    • 压测:Jmeter
Powered by GitBook
On this page
  • 指令详解
  • 1、加载和存储指令
  • 2、运算指令
  • 3、类型转换指令
  • 4、对象创建与操作
  • 5、操作数栈管理指令
  • 6、控制转移指令
  • 7、方法调用和返回指令
  • 8、抛出异常
  • 9、同步
  1. Java
  2. 字节码

字节码指令有哪些

字节码是JVM的机器语言。JVM加载类文件时,对类中的每个方法,都会得到一个字节码流。这些字节码流保存在JVM的方法区中。在程序运行过程中,当一个方法被调用时,它的字节码流就会被执行。

基础简介

  1. 方法的字节码流就是JVM的指令(instruction)序列。

  2. Java虚拟机的指令:由一个字节长度、代表着某种特定操作含义的数字(操作码Opcode)以及跟随其后的0-n个代表此操作所需参数(操作数Operaands)而构成。即指令=操作码+操作数,虚拟机中许多指令并不包含操作数,只有一个操作码。

  3. JVM中,所有的计算都是围绕栈。因为JVM没有存储任意数值的寄存器,所有的操作数在计算开始之前,都必须先压入栈中。

字节码和数据类型

在java虚拟机中,大多数的指令都包含了操作数所对应的数据类型。这一点很重要,理解了这一点很多指令都能联想记忆,例如:iload指令用于从局部变量表中加载int型的数据到操作数栈中,而fload就是加载float类型的数据。下面列出:

  1. i–int

  2. l–long

  3. s–short

  4. b–byte

  5. c–char

  6. f–float

  7. d–double

  8. a–reference

指令详解

1、加载和存储指令

每个操作如果需要从操作栈中读参数,则总是将这些参数出栈,如果操作有结果,总是会将结果入栈。

加载:将数据从栈帧的局部变量表加载到操作数栈; 存储:将操作数栈存储到栈帧的局部变量表;

  • 将一个局部变量加载到操作栈:load。例如: iload、iload_n、lload、lload_n、fload、fload_n、dload、dload_n、aload、aload_n

  • 将一个数值从操作数栈存储到局部变量表:store。例如: istore、istore_n、lstore、lstore_n、fstore、fstore_n、dstore、dstore_n、astore、astore_n

  • 将一个常量加载到操作数栈,例如: bipush、sipush、ldc、ldc_w、ldc2_w、aconst_null、iconst_m1、iconst_i、lconst_l、fconst_f、dconst_d

2、运算指令

运算指令用于对两个操作数栈上的值进行某种特定运算,并把结果重新存入到操作栈顶。 运算指令分为两种:整型(int/long)、浮点型(float/double)。对于没有直接支持 byte、short、char和boolean的算术指令使用int。

所有的算术指令如下:

  • 加法指令(add):iadd、ladd、fadd、dadd

  • 减法指令(sub):isub、lsub、fsub、dsub

  • 乘法指令(mul):imul、lmul、fmul、dmul

  • 除法指令(div):idiv、ldiv、fdiv、ddiv

  • 求余指令(rem):irem、lrem、frem、drem

  • 取反指令(neg):ineg、lneg、fneg、dneg

  • 位移指令:ishl、ishr、iushr、lshl、lshr、lushr

  • 按位或指令(or):ior、lor

  • 按位与指令(and):iand、land

  • 按位异或指令(xor):ixor、lxor

  • 局部变量自增指令:iinc(是少见的直接更新一个局部变量而无需在操作数栈中进行读写的指令)

  • 比较指令(cmp):dcmpg、dcmpl、fcmpg、fcmpl、lcmp

3、类型转换指令

类型转换指令一般用于实现用户代码的显式类型转换操作,或者用来处理 Java 虚拟机字节码指令集中指令非完全独立的问题。

宽化类型转换

  • int 类型到 long、float 或者 double 类型

  • long 类型到 float、double 类型

  • float 类型到 double 类型

窄化类型转换

i2b、i2c、i2s、l2i、f2i、f2l、d2i、d2l 和 d2f。窄化类型转换可能会导致转换结果产生不同的正负号、不同的数量级,转换过程很可能会导致数值丢失精度。

4、对象创建与操作

虽然类实例和数组都是对象,但 Java 虚拟机对类实例和数组的创建与操作使用了不同的字节码指令:

  • 创建类实例的指令:new

  • 检查类实例类型的指令:instanceof、checkcas

  • 访问实例变量(无statice修饰)和类变量(有static修饰)的指令:getfield、putfield、getstatic、putstatic

  • 创建数组的指令:newarray、anewarray、multianewarray

  • 把一个数组元素加载到操作数栈的指令:baload、caload、saload、iaload、laload、faload、daload、aaload

  • 将一个操作数栈的值储存到数组元素中的指令:bastore、castore、sastore、iastore、fastore、dastore、aastore

  • 取数组长度的指令:arraylength

5、操作数栈管理指令

虚拟机提供了一些用于直接操作操作数栈的指令,包括:pop、pop2、dup、dup2、dup_x1、dup2_x1、dup_x2、dup2_x2 和 swap。

6、控制转移指令

控制转移指令的作用是让JVM有条件或无条件地从指定指令转移到指令的下一条指令继续执行程序。

控制转移指令包括有:

  • 条件分支:ifeq、iflt、ifle、ifne、ifgt、ifge、ifnull、ifnonnull、if_icmpeq、if_icmpne、if_icmplt, if_icmpgt、if_icmple、if_icmpge、if_acmpeq 和 if_acmpne

  • 复合条件分支:tableswitch、lookupswitch

  • 无条件分支:goto、goto_w、jsr、jsr_w、ret

7、方法调用和返回指令

方法调用指令

invokevirtual:调用对象的实例方法 invokeinterface:调用接口方法,它会在运行时搜索一个实现了这个接口方法的对象,找出适合的方法进行调用。 invokespecial:调用一些需要特殊处理的实例方法:实例初始化方法、私有方法和父类方法。 invokestatic:调用static方法。

方法返回指令

ireturn:当返回值是 boolean、byte、char、short 和 int 类型时使用 lreturn:返回long类型 freturn:返回floalt类型 dreturn:返回double类型 areturn:返回对象 return :void方法、实例初始化方法、类和接口的类初始化方法的返回指令

8、抛出异常

在程序中显式抛出异常的操作会由 athrow 指令实现,除了这种情况,还有别的异常会在其它 Java 虚拟机指令检测到异常状况时由虚拟机自动抛出。

9、同步

JVM可以支持方法级的同步和方法内部一段指令序列的同步,这两种同步结构都是使用管程(Monitor)来支持的。

方法级的同步:是隐式的,即无需通过字节码指令来控制的,它实现在方法调用和返回操作之中。虚拟机可以从方法常量池中的方法表结构(method_info Structure)中的 ACC_SYNCHRONIZED 访问标志区分一个方法是否同步方法。当方法调用时,调用指令将会检查方法的 ACC_SYNCHRONIZED 访问标志是否被设置,如果设置了,执行线程将先持有管程,然后再执行方法,最后再方法完成(无论是正常完成还是非正常完成)时释放管程。在方法执行期间,执行线程持有了管程,其他任何线程都无法再获得同一个管程。如果一个同步方法执行期间抛出了异常,并且在方法内部无法处理此异常,那这个同步方法所持有的管程将在异常抛到同步方法之外时自动释放。

同步一段指令集序列:通常是由Java语言中的synchronized块来表示的。JVM的指令集中有monitorenter和monitorexit两条指令来支持synchronized关键字的语义,正确实现 synchronized 关键字需要编译器与 Java 虚拟机两者协作支持。

结构化锁定(Structured Locking):是指在方法调用期间每一个管程退出都与前面的管程进入相匹配的情形。因为无法保证所有提交给 Java 虚拟机执行的代码都满足结构化锁定,所以 Java 虚拟机允许(但不强制要求)通过以下两条规则来保证结构化锁定成立。假设 T 代表一条线程,M 代表一个管程的话:T在方法执行时持有管程 M 的次数必须与 T 在方法完成(包括正常和非正常完成)时释放管程 M 的次数相等。在方法调用过程中,任何时刻都不会出现线程 T 释放管程 M 的次数比 T 持有管程 M 次数多的情况。 请注意,在同步方法调用时自动持有和释放管程的过程也被认为是在方法调用期间发生。

来源:

Previous如何查看类编译后的字节码指令NextPython

Last updated 7 years ago

:有字节码解释示例

Java-字节码指令