热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

java字节码执行_深入浅出JVM之字节码执行

1.javap反汇编工具javap是jdk自带的反汇编工具,可以通过该命令查看编译后的class文件的常量池、字段以及方法等信息。对于下面的这个类:pu

1.javap反汇编工具

javap是jdk自带的反汇编工具,可以通过该命令查看编译后的class文件的常量池、字段以及方法等信息。

对于下面的这个类:

public class CalcCirc {

public int doCalc() {

int a=10;

int b=20;

int c=2;

return (a+b)*c;

}

}

使用javap -v CalcCirc.class可以看到该类的反汇编信息如下:

public int doCalc();

descriptor: ()I

flags: ACC_PUBLIC

Code:

stack=2, locals=4, args_size=1

0: bipush 10

2: istore_1

3: bipush 20

5: istore_2

6: iconst_2

7: istore_3

8: iload_1

9: iload_2

10: iadd

11: iload_3

12: imul

13: ireturn

.....//这里省去了LineNumberTable以及LocalVariableTable

stack=2表示在操作数栈的深度为2,这个一般是在编译的时候确定的,与方法中单一语句的执行复杂度有关,如果这条语句比较复杂,那么statck的数值就会增大。

locals=4表示有4个局部变量,源代码定义了a、b、c三个,再加上this变量,一共是4个局部变量。

args_size=1表示参数的个数,默认是1个参数,如果在方法中增加其他的参数则该数量会增加。

2.简单的字节码执行过程

字节码的执行过程需要关注的有以下内容:程序计数器、局部变量表、操作数栈。程序计数器用来指定程序当前运行的指针,也就是字节码的偏移量,对应的是字节码操作符前面的数字。局部变量表用来保存局部变量的最终结果,这里有4个局部变量,那么局部变量表的大小为4。操作数栈是保存执行过程中的实际内容,可以是局部变量的值,也可以是对象的引用。

执行第一条语句:0: bipush 10,程序计数器指向偏移量0,局部变量表中有this变量,将数字10压入操作数栈,执行后的结果如下:

​程序计数器0局部变量表0this123操作数栈10

执行第二条语句:2: istore_1,将栈顶中的数值赋值给变量1:

​程序计数器2局部变量表0this11023操作数栈

执行第三条语句:3: bipush 20,将数值20压入栈中:

​程序计数器3局部变量表0this11023操作数栈20

执行第四条语句:5: istore_2,将栈顶中元素赋值给局部变量2:

​程序计数器5局部变量表0this1102203操作数栈

执行第五条语句:6: iconst_2,将常量2压入栈中, 当int取值-1~5采用iconst指令,取值-128~127采用bipush指令,取值-32768~32767采用sipush指令,取值-2147483648~2147483647采用 ldc 指令 :

​程序计数器6局部变量表0this1102203操作数栈2

执行第六条语句:7: istore_3,将栈顶中元素赋值给局部变量3:

​程序计数器5局部变量表0this11022032操作数栈

后面的语句依次是加载局部变量1和局部变量2,iadd是从栈顶中取两个元素做加法,然后将结果放入栈中,然后加载局部变量3,imul从栈中获取两个元素做乘法,并将结果返回栈中,ireturn是将栈顶元素返回,这个返回值作为函数的返回值。

3.常用的字节码

字节码指令为一个byte整数,不同的整数代表不同的执行命令,常用的字节码指令如下:

常量入栈:

局部变量入栈: xload_n(n为0 1 2 3):x分别表示int,long,float,double,object ref,n表示局部变量下表 xaload(x为i l f d a b c s):x分别表示int, long, float, double, obj ref ,byte,char,short,该指令将从数组中取得给定索引的值,将该值压栈。比如iaload,执行前,栈:..., arrayref, index,它取得arrayref所在数组的index的值,并将值压栈。执行后,栈:..., value

出栈装载入局部变量: xstore_n(x为i l f d a,n为 0 1 2 3):将栈顶元素出栈,存入第n个局部变量 xastore(x为i l f d a b c s):将值存入数组中,iastore 执行前,栈:...,arrayref, index, value 执行后,栈:... 将value存入arrayref[index]

通用操作:nop, pop:弹出栈顶元素,dup:复制栈顶元素,复制的内容压入栈中

类型转化:i2l,i2f,d2l:将int转化为long,int转化为float,double转化为long

整数运算:iadd:int相加

浮点运算:fadd:float相加

对象操作:new:新建一个对象,getfield:获取一个对象字段,getstatic:获取静态变量

条件控制:ifeq:如果是0,则跳转,比较栈顶元素是否为0,如果是0则跳转到指定语句。

方法调用:

invokevirtual:调用实例方法,它是动态分配的调用指令,引用的类型并不能决定方法属于哪个类型,需要在实际运行的时候才能确定。 invokespecial: 调用实例初始化,父类初始化和私有方法。 invokestatic: 调用一个类(static)方法。 invokeinterface:调用类的接口方法 xreturn(x为 i l f d a 或为空):返回值,a为返回一个对象的引用

4.使用ASM生成Java字节码

ASM是java字节码操作框架,可以用于修改现有类或者动态生成新类,比如spring,AspectJ等都使用了asm框架。cglib对ASM做了一层封装,其他的框架会使用cglib来对类进行操作。

5.JIT及其相关的参数

字节码执行性能较差,对于热点代码编译成机器码再执行,在运行时的编译,叫做JIT:Just-In-Time。

所谓的热点代码是只调用的方法,或者被多次调用的循环体。jvm里会有方法调用计数器(方法调用次数)和回边计数器(方法内循环次数),通过判断这些计数器的数值是否超过阈值来判断是否将热点代码编译成机器码来执行。

-XX:CompileThreshold=1000:设置计数器的阈值 -XX:+PrintCompilation:打印出已经编译成机器码的方法



推荐阅读
  • 深入解析Java虚拟机(JVM)架构与原理
    本文旨在为读者提供对Java虚拟机(JVM)的全面理解,涵盖其主要组成部分、工作原理及其在不同平台上的实现。通过详细探讨JVM的结构和内部机制,帮助开发者更好地掌握Java编程的核心技术。 ... [详细]
  • 本文详细介绍了Java编程语言中的核心概念和常见面试问题,包括集合类、数据结构、线程处理、Java虚拟机(JVM)、HTTP协议以及Git操作等方面的内容。通过深入分析每个主题,帮助读者更好地理解Java的关键特性和最佳实践。 ... [详细]
  • 从 .NET 转 Java 的自学之路:IO 流基础篇
    本文详细介绍了 Java 中的 IO 流,包括字节流和字符流的基本概念及其操作方式。探讨了如何处理不同类型的文件数据,并结合编码机制确保字符数据的正确读写。同时,文中还涵盖了装饰设计模式的应用,以及多种常见的 IO 操作实例。 ... [详细]
  • 深入理解Java字符串池机制
    本文详细解析了Java中的字符串池(String Pool)机制,探讨其工作原理、实现方式及其对性能的影响。通过具体的代码示例和分析,帮助读者更好地理解和应用这一重要特性。 ... [详细]
  • 本文详细介绍了macOS系统的核心组件,包括如何管理其安全特性——系统完整性保护(SIP),并探讨了不同版本的更新亮点。对于使用macOS系统的用户来说,了解这些信息有助于更好地管理和优化系统性能。 ... [详细]
  • 本文总结了Java程序设计第一周的学习内容,涵盖语言基础、编译解释过程及基本数据类型等核心知识点。 ... [详细]
  • 本文作者分享了在阿里巴巴获得实习offer的经历,包括五轮面试的详细内容和经验总结。其中四轮为技术面试,一轮为HR面试,涵盖了大量的Java技术和项目实践经验。 ... [详细]
  • 深入解析JVM垃圾收集器
    本文基于《深入理解Java虚拟机:JVM高级特性与最佳实践》第二版,详细探讨了JVM中不同类型的垃圾收集器及其工作原理。通过介绍各种垃圾收集器的特性和应用场景,帮助读者更好地理解和优化JVM内存管理。 ... [详细]
  • 深入解析Spring Cloud Ribbon负载均衡机制
    本文详细介绍了Spring Cloud中的Ribbon组件如何实现服务调用的负载均衡。通过分析其工作原理、源码结构及配置方式,帮助读者理解Ribbon在分布式系统中的重要作用。 ... [详细]
  • 本文深入探讨了 Java 中的 Serializable 接口,解释了其实现机制、用途及注意事项,帮助开发者更好地理解和使用序列化功能。 ... [详细]
  • 本文详细介绍了Akka中的BackoffSupervisor机制,探讨其在处理持久化失败和Actor重启时的应用。通过具体示例,展示了如何配置和使用BackoffSupervisor以实现更细粒度的异常处理。 ... [详细]
  • XNA 3.0 游戏编程:从 XML 文件加载数据
    本文介绍如何在 XNA 3.0 游戏项目中从 XML 文件加载数据。我们将探讨如何将 XML 数据序列化为二进制文件,并通过内容管道加载到游戏中。此外,还会涉及自定义类型读取器和写入器的实现。 ... [详细]
  • 深入理解Java泛型:JDK 5的新特性
    本文详细介绍了Java泛型的概念及其在JDK 5中的应用,通过具体代码示例解释了泛型的引入、作用和优势。同时,探讨了泛型类、泛型方法和泛型接口的实现,并深入讲解了通配符的使用。 ... [详细]
  • 本文详细介绍了如何准备和安装 Eclipse 开发环境及其相关插件,包括 JDK、Tomcat、Struts 等组件的安装步骤及配置方法。 ... [详细]
  • ElasticSearch 集群监控与优化
    本文详细介绍了如何有效地监控 ElasticSearch 集群,涵盖了关键性能指标、集群健康状况、统计信息以及内存和垃圾回收的监控方法。 ... [详细]
author-avatar
独自从不变
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有