深入理解JVM 一字节码详解
今天继续总结JVM,计划本周完成这个系列的整理、总结。
本节内容枯燥,胆小者勿入!
Write Once,Run Anywhere——byteCode
byteCode 平台无关
java通过存储编译后的字节码,并将字码加载到JVM中,实现了java语言的跨平台。字节码是平台中立的代码存储格式,任意一个平台只要安装了JRE(跟平台有关),那么程序就是可以运行的。
byteCode 语言无关
除此之外,更值得注意的是字节码不仅是平台无关的,也同样是语言无关的,并不是说只有java语言才能生成byteCode,byteCode比java语言有着更强的描述性,而且JVM不与语言进行绑定,所以其他语言(Jython,groovy等),也是可以通过编译为byteCode运行在JVM中的。
Class文件
类文件 {0xCAFEBABE,小版本号,大版本号,常量池大小,常量池数组,访问控制标记,当前类信息,父类信息,实现的接口个数,实现的接口信息数组,域个数,域信息数组,方法个数,方法信息数组,属性个数,属性信息数组
}
一个byteCode文件(.class)一定对应一个java接口或者类,但是一个java接口或者类不一定对应一个.class文件,也有可能只在内存中生成。
一个class文件是一个以Byte为基础单位的二进制流,各项数据、指令紧凑的排列,中间没有任何分隔符、间隙。
javap -verbose 执行后的可视byteCode:
public class com.zs.jvm.byteCode.TestClassminor version: 0major version: 51flags: ACC_PUBLIC, ACC_SUPER
Constant pool:#1 = Class #2 // com/zs/jvm/byteCode/TestClass#2 = Utf8 com/zs/jvm/byteCode/TestClass#3 = Class #4 // java/lang/Object#4 = Utf8 java/lang/Object#5 = Utf8 m#6 = Utf8 I#7 = Utf8 <init>#8 = Utf8 ()V#9 = Utf8 Code#10 = Methodref #3.#11 // java/lang/Object."<init>":()V#11 = NameAndType #7:#8 // "<init>":()V#12 = Utf8 LineNumberTable#13 = Utf8 LocalVariableTable#14 = Utf8 this#15 = Utf8 Lcom/zs/jvm/byteCode/TestClass;#16 = Utf8 inc#17 = Utf8 ()I#18 = Fieldref #1.#19 // com/zs/jvm/byteCode/TestClass.m:I#19 = NameAndType #5:#6 // m:I#20 = Utf8 SourceFile#21 = Utf8 TestClass.java
{public com.zs.jvm.byteCode.TestClass();descriptor: ()Vflags: ACC_PUBLICCode:stack=1, locals=1, args_size=10: aload_01: invokespecial #10 // Method java/lang/Object."<init>":()V4: returnLineNumberTable:line 3: 0LocalVariableTable:Start Length Slot Name Signature0 5 0 this Lcom/zs/jvm/byteCode/TestClass;public int inc();descriptor: ()Iflags: ACC_PUBLICCode:stack=2, locals=1, args_size=10: aload_01: getfield #18 // Field m:I4: iconst_15: iadd6: ireturnLineNumberTable:line 7: 0LocalVariableTable:Start Length Slot Name Signature0 7 0 this Lcom/zs/jvm/byteCode/TestClass;
}
byteCode只存在两种数据类型:无符号数字 与 表。
无符号数字:
基本的数据类型,以u1、u2、u4、u8来分别代表1个字节,2个字节、4个字节,8个字节的无符号数字。无符号数字用来描述数字、索引引用、数据值、UTF-8编码的字符串值。
表:由无符号数字或者表构成的复合数据类型。表通常以”_info”结尾。class文件本质上就是一个表,如下图
从头到尾一项项来看:
magic:
一个4byte的无符号数字,用来确认当前文件是否是class格式文件,是否可以被jvm接收。
minor_version、major_version:
用来判断当前编译的byteCode所属JDK版本号,JDK向下兼容.
constant_pool_count:
用来记录常量池中数据类型的个数。最大值为22(1-22),也就是说常量池总共有21中数据类型。
constant_pool:
常量池 通常存储两种数据:
字面量(litera),如字符串,final常量等
符号引用(Symblic Reference),如类、接口的全限定名称、字段的名称和描述、方法的名称和描述。
access_flag:
用来描述类或接口的访问类型、修饰符等。方法内部也会有这个字段用来描述方法的修饰关键字
this class、super_class、interfaces_count、interfaces
这几个无符号数字,用来描述当前class所属的类型、父类、接口等继承与实现信息
* 字段段表集合 field_info fields*
这个表用于描述接口或类中声明的变量,但不包括方法中的局部变量。
field_info具体结构,如下:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-DEn7ml9m-1661835681889)(http:/F/img.blog.csdn.net/20170406231813514?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvbGVtb244OQ==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast)]
access_flags与之前说过,只是这里的access_flag针对成员变量(类级别的变量),用来描述这个方法是否使用了final、static、volatile等关键字修饰。
name_indexdescriptor_index这两个都是对ConstantPool的引用。
name_index:用来描述成员变量的简单名称,如int indexOf(…)这个方法,name_index在常量池中对应的描述字符串为:“indexOf”
descriptor_index:参数列表、返回值等。
对于数组类型,每一维度将使用一个前置的“[”字符来描述,如一个定义为“java.lang.String[][]”类型的二维数组,
将被记录为:“[[Ljava/lang/String;”,一个整型数组“int[]”将被记录为“[I”。
如:
int indexOf(char[]source,int sourceOffset,int sourceCount,char[]target,int targetOffset,int
targetCount,int fromIndex)
描述为:([CII[CIII)I。
注意顺序:“参数列表 返回类型”
方法表集合 method_info methods
与字段表集合类似,结构如下:
attribute_info后文详细描述。
https://kastor.opaak.org/articles/69-0xcafebabe-java-class-file-format-an-overview.htmlo
属性表集合 attribute_info
class文件本身、方法表(methods_info)、属性表(fields_info)都可以携带属性表(attribute_info),用来描述某些信息。
attribute_info属性表预定义属性如下(不完全):
属性表结构:
待续。。。
。
深入理解JVM 一字节码详解相关推荐
- java 字节码详解_Java基础篇(JVM)——字节码详解
这是Java基础篇(JVM)的第一篇文章,本来想先说说Java类加载机制的,后来想想,JVM的作用是加载编译器编译好的字节码,并解释成机器码,那么首先应该了解字节码,然后再谈加载字节码的类加载机制似乎 ...
- 深入理解JVM一字节码执行
文章目录 前言 栈帧结构 每个方法调用开始到退出,都对应着一个"栈帧"进站与出站. 运行时栈帧 栈帧-局部变量表 栈帧-操作数栈(Operand Stack) 栈帧-动态连接 栈帧 ...
- JVM(1)——字节码
1.JVM基础 1.1.JDK,JRE,JVM关系 JDK JDK(Java Development Kit) 是用于开发 Java 应用程序的软件开发工具集合,包括 了 Java 运行时的环境(JR ...
- JVM之内存结构详解
对于开发人员来说,如果不了解Java的JVM,那真的是很难写得一手好代码,很难查得一手好bug.同时,JVM也是面试环节的中重灾区.今天开始,<JVM详解>系列开启,带大家深入了解JVM相 ...
- java的String类源码详解
java的String类源码详解 类的定义 public final class Stringimplements java.io.Serializable, Comparable<String ...
- JVM之类加载阶段详解
JVM之类加载阶段详解 类加载阶段总览 加载 获取二进制流 将字节流转换为运行时数据结构 堆中生成Class对象 特殊 连接 验证 准备 解析 名词解释 何时进行 解析哪些类型 初始化 类 接口 使用 ...
- JVM运行时区域详解
转载自 JVM运行时区域详解 我们知道的JVM内存区域有:堆和栈,这是一种泛的分法,也是按运行时区域的一种分法,堆是所有线程共享的一块区域,而栈是线程隔离的,每个线程互不共享. 线程不共享区域 每个线 ...
- Go 语言 bytes.Buffer 源码详解之1
转载地址:Go 语言 bytes.Buffer 源码详解之1 - lifelmy的博客 前言 前面一篇文章 Go语言 strings.Reader 源码详解,我们对 strings 包中的 Reade ...
- python接口自动化(七)--状态码详解对照表(详解)
简介 我们为啥要了解状态码,从它的作用,就不言而喻了.如果不了解,我们就会像个无头苍蝇,横冲直撞.遇到问题也不知道从何处入手,就是想找别人帮忙,也不知道是找前端还是后端的工程师. 状态码的作用是:we ...
最新文章
- Google 神秘 Fuchsia OS 的开源线索
- Linux高性能网络:协程系列08-协程实现之调度器
- listview与gridview点击时的背景色取消
- 上帝的玩偶:haXe语言
- Ubuntu如何搭建Django与Flup和Nginx环境?
- 中快捷搜索_同事用1分钟,我用半小时,原来是因为这8个Word快捷键,秒杀一切办公技巧...
- 深入解读 MySQL 底层原理,让性能“飞起来”的方法总结
- php怎么使用插件下载,怎么使用下载的jquery插件
- 智能环境监测产品浪涌防护整改之TVS管
- NPN 、PNP 三极管开关形式的典型接法(注意上下拉电阻)
- 5G的遮羞布被撕下了,双十一最畅销的手机竟然是4G手机
- c语言 eval,分享:自己写的eval函数
- 好性格让孩子受用终生
- 交流异步电机的Modelica模型
- 前TT(前T/T)与后TT(后T/T),以及信用证(LC,L/C)付款方式比较
- linux限制message日志大小,message显示rsyslog日志服务警告信息due to rate-limiting
- linux 下 gcc编译程序时,-I(大写i) 与-L(大写l)-l(小写l) 的作用
- Scratch之顺序、循环、选择三种程序结构
- hdu1814 Peaceful Commission 2-sat
- 如何用计算机打出立方,立方米符号怎么打出来