• JVM学习一


    java从编码到执行的过程

    在这里插入图片描述
    首先执行javac将java文件编译为class文件,然后执行java命令的时候,这个class文件会被
    ClassLoader加载到内存里面,同时也会将java类库加载到内存,完成之后会调用字节码的解释器
    或者是即时编译器来进行解释或编译,最后由执行引擎开始执行,执行引擎下面对应的则是硬件了。

    JVM被我们称为跨语言的平台(目前能在JVM上跑的语言是很多的),Java是跨平台的语言
    在这里插入图片描述
    任何语言只要符合class的规范则可以丢给JVM执行
    在这里插入图片描述
    所以就推导出JVM就是一种规范:
    在这里插入图片描述

    常见JVM实现

    在这里插入图片描述

    JDK,JRE,JVM之间的关系

    JDK包含了JRE和开发的一些库,
    JRE包含了JVM和核心类库
    在这里插入图片描述

    class文件组成

    MagicNum:4字节,固定值0xCAFE BABY,class文件的代表
    Minor Version,Major Version:class文件的版本号【jdk7默认为51,jdk8默认为52】
    constant_pool_count:常量池
    constant_pool :常量池具体的实现
    长度为constant_pool_count-1的表
    access_flags :访问修饰符
    this_class:当前类是啥名
    super_class:父类是啥名
    interfaces_count :接口数量
    interfaces:分别是哪些接口名
    fileds_count : 有哪些属性
    fileds:各属性的具体信息
    methods_count:有哪些方法
    methods:具体是哪些方法
    attributes_count-u2:还有别的附加的方法有哪些
    attributes:附加属性的具体信息

    class文件解读

    0034 : 316的一次方 + 416^0 = 52 (说明是java8的)
    在这里插入图片描述
    也可以通过下载jclasslib插件查看字节码信息
    在这里插入图片描述
    其中访问标志(access_flag):占用两个字节分别是(ACC_SUPER,ACC_PULIC相与)
    在这里插入图片描述
    this_class:当前类的全类名,cp_info#2,指的是这个名字在常量池里面的2号存了这个名字
    super_class:常量池里面的三号存了一个Object.class
    再来看常量池:

    在这里插入图片描述
    如上图前面的数字代表标记值
    下面来一个简单的类:
    在这里插入图片描述

    通过查看字节码信息,下图表示的常量池长度为16:
    在这里插入图片描述
    其中第一个代表的是方法的引用信息,这个方法的引用信息里面包含了指向CONSTANT_Class
    _info的索引项,以及NameAndType的索引项目,如上图分别指向了3号的声明类信息的常量池,
    以及13号的内容NameAndType,指的是方法的名字和描述符是什么【init代表构造方法,()V代表这个方法没有任何参数且返回值为V{V代表void}】
    在二进制中则可以这样看:
    在这里插入图片描述
    0a代表的是tag=10的methdoref_info,然后后面两个字节的 0003和000d分别代表指向的声明的class类型
    和13号内容的NameAndType。如上图的 0a00 0300 0d 代表的是常量池的第一号内容。
    第二号常量池是07开头,然后找到图上的07索引,代表的是我们的class_Info,和下图对应上了:
    在这里插入图片描述
    然后里面说这个02指向了常量池的14号位置,后面两个字节为000e,正好是14位置。
    在这里插入图片描述
    接下来第三号常量池,又是一个07【class_info】,然后后面的两个字节为000f,指向了十五位
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    类全限定名:
    在这里插入图片描述
    属性名称
    在这里插入图片描述
    字符串源文件名:
    在这里插入图片描述
    类普通名称:
    在这里插入图片描述
    普通类名:
    在这里插入图片描述
    表示实现了哪些接口,后面的字段代表有哪些属性
    在这里插入图片描述
    code代表方法的具体实现:
    在这里插入图片描述
    在这里插入图片描述
    aload0对应了其上的2a部分
    在这里插入图片描述
    找到对应java汇编指令的说明
    在这里插入图片描述
    将本地变量里面的第零项放到栈里面
    invokespecial
    在这里插入图片描述
    在这里插入图片描述
    如上后面带了两个字节是代表,指向常量池的第几号【如上是常量池第一号】,调用java/lang/object的那个构造方法【因其构造方法是空的,所以调用父类的构造方法】
    其后跟一个b1,是代表方法结束:
    在这里插入图片描述

    包含thisclass以及superclass
    在这里插入图片描述
    将类改成如下形式:

    public class T0100_ByteCode01 {
        int i = 888;
    }
    
    
    • 1
    • 2
    • 3
    • 4

    在这里插入图片描述
    调用invokespecial,调用初始化方法,然后又调用一次aload0将this装进去,将888扔进去,将888putfiled在2号对应的那个i变量值里面去

    类加载-初始化

    在这里插入图片描述
    首先分为三大步:loading->linking->initializing【静态变量赋初始值】
    其中linking分为三步骤:
    verification【校验class文件是否符合标准(如cafe babe)】->preparation【
    class文件的静态变量赋默认值,如int赋值为0】->resolution【
    常量池里面用到的符号引用转换为直接能访问到的内存地址】
    1.符号引用:符号引用以一组符号来描述所引用的目标,符号可以是任何形式的字面量,只要使用时能够无歧义的定位到目标即可。
    例如,在Class文件中它以CONSTANT_Class_info、CONSTANT_Fieldref_info、CONSTANT_Methodref_info等类型的常量出现。符号引用与虚拟机的内存布局无关,引用的目标并不一定加载到内存中。在Java中,一个java类将会编译成一个class文件。在编译时,java类并不知道所引用的类的实际地址,因此只能使用符号引用来代替。比如org.simple.People类引用了org.simple.Language类,在编译时People类并不知道Language类的实际内存地址,因此只能使用符号org.simple.Language(假设是这个,当然实际中是由类似于CONSTANT_Class_info的常量来表示的)来表示Language类的地址。各种虚拟机实现的内存布局可能有所不同,但是它们能接受的符号引用都是一致的,因为符号引用的字面量形式明确定义在Java虚拟机规范的Class文件格式中。
    2.直接引用,直接引用可以是:
    (1)直接指向目标的指针(比如,指向“类型”【Class对象】、类变量、类方法的直接引用可能是指向方法区的指针)
    (2)相对偏移量(比如,指向实例变量、实例方法的直接引用都是偏移量)
    (3)一个能间接定位到目标的句柄
    直接引用是和虚拟机的布局相关的,同一个符号引用在不同的虚拟机实例上翻译出来的直接引用一般不会相同。如果有了直接引用,那引用的目标必定已经被加载入内存中了。

  • 相关阅读:
    【SpringBoot】SpringBoot怎么接收前端传递过来的数组
    Unity可视化Shader工具ASE介绍——8、UI类型的特效Shader编写
    CTF-misc练习(https://buuoj.cn)之第二页
    Java面向对象学习笔记-4
    前端笔试题总结,带答案和解析(二)
    面向对象程序设计
    vue介绍,引入及使用,优缺点,基本指令,双向绑定数据,类名灵活操作,设计模式(MVVM和MVC)
    git同步其他分支方法
    求解置换流水车间调度问题PFSP的关键路径-附Matlab源码
    写个简单的管理数组指针的智能指针
  • 原文地址:https://blog.csdn.net/lsdstone/article/details/126474269