目录:
java虚拟机汇总

  1. class文件结构分析 <<== 现在位置
    1).class文件常量池中的常量项结构
    2). 常用的属性表的集合
  2. 类加载过程
    1).类加载器的原理以及实现
  3. 虚拟机结构分析
    1).jdk1.7和1.8版本的方法区构造变化
    2).常量池简单区分
  4. 对象结构分析
    1).压缩指针详解
  5. gc垃圾回收
  6. 对象的定位方式

内容
jvm运行时都是运行.java编译好的.class文件
这里先了解下class文件长什么样以便后续的理解

本文外引的链接为(class文件常量项结构)
(常用的属性表种类集合)

下面开始,文章篇幅较长,而且比较干,萌新必须静下心来看,大佬随意(doge)

例如:创建一个类文件

class Test{int a;public static void main(String []args){}
}

编译后的class文件如图所示

在这里我们把一个字节的大小用u1表示, 则占用u4就是占用4个字节,对应上图4个红圈
整个class文件的结构如下图所示,(再此感谢此图的制作者) 建议将此图保存到一旁以便查看

下面开始讲解各部分的内容

魔数

占用4个字节,则下图画红圈部分表示为魔数

截取下来表示为cafeBabe 翻译为咖啡宝贝(可以看出取名挺幽默)

魔数(Magic Number),它的唯一作用是确定这个文件是否是能被虚拟机接受的Class文件。使用魔数而不是扩展名来进行识别主要是基于安全方面的考虑,因为文件扩展名可以随意地改动,说白了就是,不是以这个开头的文件不处理

次版本号和主版本号

每个版本号占用u2,即两个字节,则下图画红圈部分分别表示次版本号和主版本号

截取下来为主:52, 次:0,即52.0版本 对应Java的jdk1.8
JavaSE 8 = 52 (0x34 hex),
JavaSE 7 = 51 (0x33 hex),
JavaSE 6 = 50 (0x32 hex),
一句话来说次版本号和主版本号就是给jvm明确此类编译的jdk版本,以便判断是否支持某些操作

常量池个数


截取下来表示为常量池有17个数据项,但实际后面只有16个数据项
(设置成1–16 16个的话,如果某些引用需要指向空则就直接指向0,表示空,到后面讲属性和方法的时候会遇到),
此后会跟上[0]–[15]个数据项,总共16个以数组形式表示
注:此时xx_index指向3,则表示寻找第3个数据项[2]

,每一个数据项都将被表示成表,那紧接着下面的16个常量就是这个常量池中所有的内容了,下面讲解每个常量项的结构

常量项(数据项)


在这里为什么我会知道下一项的长度呢,其实每一个常量项都是有结构的,先不要着急,往后看

每个常量项的第一个字节 对应上图中的tag标志 找到对应的结构 (在此分析前四项作为举例)
——————————————————————————————————————

比如画红圈的第一项,开头是0A则为10,查找上表

下面代码是CONSTANT_Methodref 的结构 占用五个字节 (读注释!
(在此标注了所有的常量项结构)
此Methodref显然想要表示的是一个方法

CONSTANT_Methodref_info {u1 tag;   //Methodref固定是10,也是这个类型的常量项的唯一标志u2 class_index;   //此时是00 03  即3 表示引用常量池中第3个常量项 u2 name_and_type_index;   //此时是00 0E  即14 表示引用常量池中第14个常量项
}

注意:此时我们在分析的是第一个常量项
在这里直接指出
------第14个常量项表示的是一个0C标识符的nameAndType 它又指向了第6,7 个常量项 和 ()V
------第3个常量项表示的是一个标志07的类名,它又指向了一个以01标识的utf8字符串 java.lang.Object
总之 0A 00 03 00 0E 表示了一个 方法名称,构造方法(隐式声明了) java.lang.Object 包里的 void()初始化方法
以后不再赘述分析
—————————————————————————————————————————————
同理分析出第二项

tag为7,查找对应表

下面代码是CONSTANT_Class的结构 占用三个字节

CONSTANT_Class_info {u1 tag;         // 同理,此类型的就固定为7u2 name_index;    // 索引值,在此可以发现所有以**_index结尾的都是指向第n个常量项,此时n是00 0F
}

这里指出第0F ,第15个常量项是 Test字符串 其实这个Class就表示了一个类的名称
————————————————————————————————————
同理三

tag是7,则结构和第二项一样,不做赘述
——————————————————————————————————————
第四项

发现tag是1,此类型就是utf-8字符串类型

CONSTANT_Utf8_info {u1 tag;              // 1u2 length;          // length表示接下来 字符串 有多少个字节,此时是00 01,下面有1个字节长度字符u1 bytes[length]; // 字符串字节数组 上面length如果是8则这一项就是8字节的字符数组 此时是1个长度 61 用utf-8解码是 a// 61表示为a即对应我们int a;的变量名字
}

————————————————————————————————————————————
分析到此结束
此图为全部的16个常量项,
一句话:这部分就是常量池,装载了全部类的字段,方法,类名称的信息;

访问标志(access_flags)

来到这里不妨回头看看主图,我们现在分析到了访问标志,不要忘记回头看此图

访问标识来表明这个class有什么修饰符 只有两个字节
以下为访问标识符,
举例: 原来是00 20(看下表中ACC_SUPER描述,最低限度必须有此标志)
如果:类是public类型-的,则第一个ACC_PUBLIC为true 则加上00 01 ,结果为00 21
如果:类还是 final类型-的,则第二个为true,再加上00 10 ,结果为00 31
如果此时不是其他的任何选项(不是接口则第4个02 00不用加,不是abstract类型则第5个不用加
。。。) 那么该标识符就是 00 31


来看我们的class文件

00 20
表示其他的标识符都没有
我们做如下改动
将类改为public,重新编译,再看class


00 21 = 00 20 + 00 01 ( 加了public)
表示为public 的类
设置的数值刚好不会出现相加和其他状态相等的情况,很巧妙
一句话 访问标识就是只用两个字节表示了这个类的修饰符有哪些

类、父类(This class,Super class)

(看主图)不要忘记我们进度到哪了
这个很简单,记得我们在常量池时会有 xx_index 引用引向常量池中的第n个常量项吗,

下面看看我们class文件中的This class,Super class是哪几个

这两个标识符也都是一个两字节的引用,我们class文件中,分别引向常量池中00 02的第二个常量项和00 03 第三个常量项,这里就不带大家去找第二,三个常量项了

接口个数

。。。。就表示该类文件实现了接口的数量;没有就是00 00 ,有一个就是 00 01没啥好讲的

在这里对我们的class文件作出修改

使其实现一个接口,则看下图,变为了00 01

接口1,接口2.。。。

这个就没得说了,前面接口数量是几,后边这个两字节的接口的长度就为几,这两个字节也是指向常量池的索引

因为前面长度是1,所以接下来的一个字节的长度是索引,00 04 ,指向常量池第4个常量项

字段个数,字段1,字段2。。。。

进行到这里我们就只差三个了:字段 方法 和属性 加油

和上面的一样,字段个数表示我们有几个字段,此时为00 01,1个 因为我们只定义了一个变量 int a;

以后跟着n(此时是1)个字段,当然这个字段没有固定字节数,因为和常量项类别一样,有很多种类型,所以长度也不确定,接下来我们看下通用结构

field_info {u2             access_flags;     // 字段访问标志u2             name_index;     // 字段名称u2             descriptor_index; // 字段类型u2             attributes_count; // 属性数量attribute_info attributes[attributes_count];  // 属性项
}

在这里因为我们第四个 attributes_count 为0 ,所以总长度(算字段个数)为10字节
下图所示

分析第一个 access_flags
----其实跟之前我们讲访问标识的时候一样,不一样的是这次的访问标志修饰符是修饰字段的
所以在标志名称上有些不同

这里加一张图用另一种方式表示我们的修饰符(在此感谢此图的制作者)

我们的访问标识符为00 00 表示什么修饰也没有 毕竟我们只定义了一个 int a;

分析第二个 name_index(此字段的字段名称)
CONSTANT_Utf8类型常量项的索引,里面存储了字段描述符
这个没啥说的就一个两字节的,指向字符串常量池的索引

此时我们是00 05,表示引用常量池中的第5个常量项
在这里直接指出 是一个CONSTANT_Utf8类型常量项 其值为 a ,表示我们字段的名字是a
分析第三个 descriptor_index(含义字段类型)
CONSTANT_Utf8类型常量项的索引,里面存储了字段描述符
和上面一样,一个两字节的,指向字符串常量池的索引

此时我们是00 06,表示引用常量池中的第6个常量项
但是这个我们要说一下
通过这个索引查找到第6常量项,如下图,类型为1,则为字符串类型的 长度为1 则下面49为字符串的值 ,对应右边翻译表的:大写 I,I 有什么意义呢


上表表示的就是类型了,可以看到我们大写I表示了一个int类型的含义,descriptor_index含义为这个字段的字段类型 ,则表示此字段为int类型 int a

分析第四个 attributes_count
表示这个字段所拥有的attribute类型的个数,如果是00 01 就表示一个
分析第五个 attributes[attributes_count]
就是一个长度为 attributes_count,类型是:属性类型的数组
这个类型我们暂时不分析,到后面讲到 属性 时一起讲

一句话总结
就是一个装有我们定义的所有属性的数组,长度为字段个数,里面的每一个表信息都表示一个字段

方法个数,方法1,方法2。。。。

这个就不说了因为结构和字段一摸一样,减轻大家的负担

上图为方法数量,3个方法
下面为方法表的结构

method_info {  u2 access_flags; //访问修饰符。。参照下图u2 name_index;  // 一样。。。。u2 descriptor_index; //一样。。。u2 attributes_count; //一样。。。attribute_info attributes[attributes_count];
}

access_flags的修饰类型

则 方法个数,方法1,方法2。。。。对应我们class文件中的哪些呢

这些在属性中会讲

一句话总结
就是一个装有我们定义的所有方法的数组,长度为方法个数,里面的每一个表信息都表示一个方法

属性个数,属性1,属性2。。。。

这是最后一个了,但是最难的才开始(属性要讲很多,,一次理解不了的可以收藏过后再看)
上面所说的字段方法的最后都有一项:属性项数组,里面装的就是这个类型了
其实class文件还有一个属性表,就是上面那张图没有覆盖掉的最后一部分
官方的话:
在Class文件、字段表、方法表都可以携带自己的属性表集合,用于描述某些场景的专有信息。属性表中不要求各个属性表具有严格的顺序,只要不与已有属性重名即可。下表列举了一些java虚拟机预定的属性。
不去管他什么意思,就只了解字段,方法中都有属性数组就可以了,下面我们来分析方法中的属性表(因为我们字段表的属性表长度为0,所以分析方法表)

还是上面这张图,我们来一个一个分析

上面的图高亮部分为方法长度 ,表示有多少个方法表如图是三个
第一个

上图高亮是第一个方法表的前三个字段

access_flag为00 01
name_in…等,(将方法时说过了不说了)
则第四个属性 attributes_count为

一个长度
接下来的就是一个属性表数组了,里面只有一个属性表

上图是整个这个属性表的内容,直接看前两个字节 00 09,这是一个引用,引用常量池里的,utf-8类型常量项
00 09 第9个常量项 我们看下

这是第9个常量项,其值是Code表示这个属性表是一个Code类型的属性表
然后下图看00 09 后面的四个字节,他表示整个这个属性表还有多少字节 00 00 00 1D,29个长度

向后延申29个字节(记住这个29是Code类型的属性表里边的内容,不算前6个字节),如下图,属性数组结束,第一个方法也随之结束,上面的00 09 和 00 00 00 1d,是所有的属性表的共有属性,一个是该属性表的类型,一个是该属性表的 属性值长度(属性值长度=属性表长度-6),6就是我们前面的00 09 和 00 00 00 1d,6个字节


如上图属性表的
前两个个字节为一个指向常量池里的一个utf8类型的字符串,表示此属性的类别,
中间4个字节为整个属性表的接下来的长度
然后后面跟着的就是attribute_length个字节了,

我们这里类型是Code那么Code属性表里都是什么呢

可以看到我们Code表前两个字段是我们上面分析过的,所有属性表都有的,这里跳过这两个,下面看内容,也就是29个字节里分别是什么


29个字节中的前两个字节,也就是对应

max_stack 代表了操作数栈(Operand Stacks)深度的最大值。在方法执行的任意时刻,操作数栈都不会超过这个最大值。虚拟机运行的时候需要根据这个值来分配栈帧(Stack Frame)中的操作栈深度
根据我们总体学习框架,我们还没了解到栈,跳过

接下来所有的字节请对照Code属性表一个字节一个字节自行分析(不难),总之全部过后

第一个方法结束,我们就进行到这了,下一步我们分析第二个方法,再带大家走一遍

这6个字节是第二个方法的前面的一些属性
,不做分析 接下来 的00 01是属性表长度,
再接下来的00 09是第一个属性表的名称类别,去常量池里找,发现还是Code属性表,
再接下来四个字节00 00 00 19 是属性表接下来的长度,25个字节。。。。。。不分析了总之第二个方法(含属性表)如下图

第三个方法

最后我们分析到了class文件的属性表

前两个字节的信息表示class有多少属性表 00 01 ,1个 然后跟着一个属性表
最后带大家分析一边属性表了
00 0E表示属性表种类,查找字符常量池的第14个

可以看我们右边的翻译,为sourceFile类型的,上次和上上次分析的是Code表,那么这个类型的属性表结构是什么?如下图

SourceFile属性用于记录生成这个Class文件的源码名称。
在接下来的四个字节为长度00 00 00 02,接下来还有两个字节
sourceFile_index,以_index结尾的不用说,指向常量池的索引,我们看下第00 0F个常量项

是Testt.java(这是我写的另一个java文件编译的,就换了名字)

可见只是记录了我们原java文件名称

到此我们的属性分析就。。。还没结束,我们全部类型的属性表很多,包括Code表里面的Code属性(方法内容),因为此篇太长了所以转到(常用的属性表种类集合)
为大家讲解

此篇分析class文件源码结束,这只是jvm的开始,希望大家自己再走一遍流程,熟悉下操作

还有此篇的转发无需请求我的同意,本人默认同意转发哈

class文件详解(全过程举例加图解)相关推荐

  1. Qt pro 文件详解

     Qt pro 文件详解 1. TEMPLATE  变量TEMPLATE描述了为建立目标文件而采用何种模板,即生成何种形式的Makefile文件.Qmake  工具定义了5种模板:   a. 应用 ...

  2. INF文件详解(32位64位兼容INF)

    INF文件格式要求 一个INF文件是以段组织的简单的文本文件.一些段油系统定义(System-Defined)的名称,而另一些段由INF文件的编写者命名.每个段包含特定的条目和命名,这些命名用于引用I ...

  3. Linux中/proc目录下文件详解

    Linux中/proc目录下文件详解(一) 声明:可以自由转载本文,但请务必保留本文的完整性. 作者:张子坚 email:zhangzijian@163.com 说明:本文所涉及示例均在fedora ...

  4. javaweb web.xml文件详解

    web.xml文件详解 前言:一般的web工程中都会用到web.xml,web.xml主要用来配置,可以方便的开发web工程.web.xml主要用来配置Filter.Listener.Servlet等 ...

  5. linux /proc目录文件详解

    Linux中/proc目录下文件详解(一) /proc文件系统下的多种文件提供的系统信息不是针对某个特定进程的,而是能够在整个系统范围的上下文中使用.可以使用的文件随系统配置的变化而变化.命令proc ...

  6. STM32(Cortex-M3)启动过程+IAR中xcl及icf文件详解

    一:STM32(Cortex-M3)启动过程(入口地址) ARM7和ARM9启动时从绝对地址0X00000000开始执行复位中断程序,即固定了复位后的起始地址,但中断向量表的位置是可变的. Corte ...

  7. Linux中/proc目录下文件详解(二)

    Linux中/proc目录下文件详解(二) /proc/mdstat文件 这个文件包含了由md设备驱动程序控制的RAID设备信息. 示例: [root@localhost ~]# cat /proc/ ...

  8. Linux配置启动挂载:fstab文件详解

    Linux配置启动挂载:fstab文件详解 [日期:2014-12-23] 来源:Linux社区 作者:aceking10 [字体:大 中 小] fstab文件介绍 fstab文件包含了你的电脑上的存 ...

  9. PE文件详解(教程1-7)

    PE文件详解(教程1-7) ========================================= PE教程1: PE文件格式一览 PE 的意思就是 Portable Executable ...

最新文章

  1. mongodb和python交互
  2. springBoot+springSecurity 数据库动态管理用户、角色、权限(二)
  3. 一个家系突变分析一篇 SCI | 文章解析
  4. 笨方法“学习python笔记之字典
  5. pytorch学习笔记(十一):pytorch实现多层感知机
  6. jquery读写cookie
  7. 测试一下各浏览器对CSS3的支持
  8. uniapp ios时间戳获取不到_个人小程序uniapp实战开发(三):数据库设计与文章列表...
  9. (四)DIH导入结构化数据
  10. 基于Nginx搭建RTMP-HLS视频直播服务器(推流+拉流)
  11. HTML炫彩按钮,炫彩流光按钮 html+css
  12. matlab-梯形积分
  13. 如何保存微信视频号的视频到本地?
  14. (华为社招岗位,部门---上海海思,GTS,海思,2012,华为云):北京北京北京!
  15. 怎么重置imac_[重置系统]如何重置Mac电脑到出厂状态
  16. 输入邮箱判断邮箱是否合法
  17. Python爬虫识别中文字符和标点符号
  18. MD5 加密安全吗?
  19. 85-决策树解决回归问题
  20. ffmpeg中支持的音频互相转换的采样格式和声道分布

热门文章

  1. fasta文件中序列的排序
  2. PAT甲题题解-1010. Radix (25)-二分搜索
  3. Android 5.0以上heads up通知
  4. Angular2 - Starter - NgModule
  5. IOS学习笔记——ViewController生命周期详解
  6. (原)python爬虫入门(2)---排序爬取的辽宁科技大学热点新闻
  7. LIve Writer图片自动水印,自动居中,自动为原始大小的设置方法.
  8. 打算做个单用户博客,引用收藏一下zblog的话
  9. JSK-25 两数之和【暴力】
  10. 矩阵、优化理论常用记号