一、jvm调优学习记录之.class文件篇

一、jvm调优学习记录之.class文件篇

最近由于工作上的问题,对java虚拟机产生了浓厚的兴趣,这里做下学习记录,欢迎大佬们的指正。

一、jvm含义解读

jvm,Java Virtual Machine即java虚拟机。jvmjava语言其实没有任何关系,这是很多人的误区。他只是一种规范,是虚构出来包含字节码指令集和内存管理(堆、栈、方法区等)的计算机。

.java文件通过javac编译为.class文件后的类加载过程在jvm中进行。所以,任何语言,只要是通过了编译,成为.class文件,就可进入jvm中执行。
在这里插入图片描述
如图所示,本文将对前期编译出的.class文件进行分析。

二、.class文件分析

class文件从本质上来说,是二进制字节流。但是计算机是无法直接读取执行二进制串的,所以jvm应运而生解决了这个问题,它可以把Class文件的二进制翻译成计算机能够读懂的形式。

1、class基本信息

我这里是在idea中下载了BinEd插件,用以观察class文件的二进制源码。
在这里插入图片描述
新建一个空类

public class ByteCode01 {
}

打开可以看到如下十六进制码,各位都分别对应了class文件中的版本号、常量池长度、常量池、接口等。
在这里插入图片描述
​ 其中,CA FE BA BE为16进制八位一字节的4字节magic_number,它表明了这个文件是一个符合class文件定义规范的文件。

​ 之后,000行04-05位的两字节为MinorVersion,是小版本号,如:xx.0这里的0即为小版本号。06-07位的两字节为MajorVersion,大版本号,如:8.x这里的8即为大版本号。所以图中的小版本号为0,大版本号十六进制0034换算成十进制也就是52,也就是说我们的版本号为52.0,也就是对应JDK1.8。打开class文件,如图:
在这里插入图片描述
​ 再往后看,08-09位的两字节为Constant_Pool_Length,常量池长度。当前的常量池长度为00 10,换算成十进制就是16,但实际只保存15个对象,因其会保留0位存储索引指向。

​ 常量池长度设置了,接下来当然就是常量池里的对象了。在idea中下载了jclasslib插件,观察class文件bytecode结构信息。ByteCode01打开,可以看如下图所示:
在这里插入图片描述
​ 该工具将一般信息做了相对javap的可视化展示,版本号、常量池计数等都进行了相对可视化的展示。其中,访问标志(access_flags)为0x0021,它代表什么呢?这里有一个access_flags的位运算对应关系图。
在这里插入图片描述
​ 那么,0x0021也就是0x0001与0x0020,这样子的表示方式就使得它可以仅用两个字节就将很多内容进行表述。

2、常量池

​ class文件最重要的常量池环节来了,把常量池弄明白基本也就没什么问题了。常量池仅仅是常量类型就有很多,下图其中部分类型展示:
在这里插入图片描述
​ 中间缺失tag2,是为标记位,常量池的每一个类型都会有一个1字节的标记。那么,怎么看呢?我们拿Methodref举例,tag:10为该类型的标记,index为指向声明方法的类或者接口描述符CONSTANT_Class_info的索引项,占两字节,另一index指向描述符索引在tag[12]中,图中未给出,占两字符。

​ 回到本文的空类中,点开常量池[01],如下图:
在这里插入图片描述
​ 类名(即第一个index)指向tag[3],名称和描述符(即第二个index)指向tag[13],分别如下如所示
在这里插入图片描述
​ 可以看到,[03]中类指向了[15],而[15]为Utf-8字符串,即该声明方法的类名为Object类。而[13]指向了[4]、[5],即该方法的类型为init(构造)方法,且()表示无参数,v表示返回值是void,也就意味着这是一个Object类下的默认无参构造方法,也就是说我们在创建一个类时,若类内没有构造方法,编译自动填加默认无参构造方法。回到class文件的二进制里去看,如下图
在这里插入图片描述
​ 000行的0A-0E为常量池中的第一个元素,0A位为其标志位,转为十进制则为10,10对应的则是CONSTANT_Methodref_info0B-0C则是它的第一个索引00030C-0D则是第二个索引000D,也就是十进制3和13。 回到常量池,继续往下看
在这里插入图片描述
在这里插入图片描述
​ [4]为Utf-8字符串,表示[3]方法名称为init。[5]为方法的描述符,()V为其书写规范,下图为规范举例及规范对应
在这里插入图片描述
在这里插入图片描述
​ 再之后的[6]、[7]、[8]分别为类方法与类属性的属性名称,其余也均是字符串,不一一赘述了。

​ 接下来则是方法实现部分,可以看到是属性名称,然后下面是字节码
在这里插入图片描述
aload_0,感兴趣的小伙伴,可以去下载JAVA虚拟规范,查询java汇编指令aload_0
在这里插入图片描述
​ 那么aload_0是做什么的,点击aload_0查看jvm规范,可以看到如下,大概意思为将索引为0(基本为this)的局部变量压到操作数栈中。
在这里插入图片描述
​ 变量放到栈中后,执行第二条指令invokespecial,调用其实例初始化方法即构造方法。
在这里插入图片描述
​ 第三步,return。再回到二进制中去看该方法实现部分,aload_0对应十六进制0A0A之后则是B7,看到上图JVM规范,也就是invokespecial
在这里插入图片描述
​ 执行完invokespecial,则是return(方法结束),查看JVM规范
在这里插入图片描述
B1在120行,00 列,那前两个字节里的0001是什么呢?回到invokespecial规范里可以看到,是它带了两个参数,分别指向常量池中的位置,01也就是一开始分析的Object构造方法。所以,2a-b1即为一个构造方法的具体实现。实现流程:虚拟机读到2a开始对this进行压栈,b7知道调用构造方法,00、01为其参数指向java.lang.Object,即为Object类构造方法,return方法结束。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值