JVM-类加载与运行区详细分析(一)

news2024/11/25 16:44:08

目录

一、为什么会有类加载机制

二、类加载机制原理是什么

1、什么是类加载器:宏观

2、类加载器工作原理

1、装载

2、链接

3、初始化

3、何为装载的机制:微观

4、上面既然我们已经知道了啥是双亲委派了,那么怎么去破坏呢?

三、类加载机制分析

1、类加载

1、那么何为对应的区域?

2、为什么是静态存储结构?

2、链接

1、验证

2、准备

3、解析

3、何为初始化?

四、运行时数据区

1、运行时常量池

2、虚拟机stacks

3、本地方法栈

4、寄存器pcthe pc register

五、总结

六、详聊运行时数据区

1、方法区(Meathod Area)

2、堆(heap)

3、Java虚拟机栈

4、总结

七、聊聊官网没有介绍的

1、方法区

2、运行时数据区与内存模型

3、java虚拟机栈,执行方法的时候,到底经历了什么?


一、为什么会有类加载机制

我们首先从jdk组成开始切入,再到jdk在java中作用,在到jvm中javac过程。

javac(编译)只是做了由源码到类格式的转换,里面的内容并没有进行这样一个变幻,只不过是采用另外一种方式表现出来了。就是转化为 jvm能够识别的格式。

javac:就是做了编译原理方面的事情词法分析->语法分析->语法树->字节码生成器->class文件。

所以其他编译器只要也按照这个clas格式去编译,那么他也就是能在jvm中去运行。所以此时此刻jvm也是能够运行其他运行语言的代码。

由此而知,这个class就该交给jvm运行了,那么下面我们就可以去看看到底jvm到底干了什么事?

那么class交给jvm你肯定是通过某种机制去交给jvm..所以这一块加载就涉及到:面试常问的“类加载机制。

所以此时我们就知道类加载器他到底是为了干嘛的,为什么要有他?

他发挥的作用其实就是从类文件到jvm这个过程中它必须有一个这样的机制将我们的class文件交给jvm.这就是我们类加载机制。

所以我们就顺其自然的从class类到类加载机制这一块。

二、类加载机制原理是什么

1、什么是类加载器:宏观

比如我们现在要把生成的class文件通过类加载机制加载到jvm,那么如果使我们自己去实现这个类加载机制

那么我们会怎么去实现呢?其实就是类加载步骤。

我们不管怎么做,其实他的第一步一定有一个操作:就是他先去找到class类文件的位置。不管你是在磁盘当中,还是网盘当中,还是数据库。

所以第一步我认为他一定是先找到他,就是类文件的全路径。

那么接下来找到之后干什么呢

找到之后不就是交给jvm吗。但是我们是如何去交的,那么他一定也有一个顺序的。

比如从两个大的维度能看到的是

第一步肯定是要把类文件信息交给jvm(类文件的所有描述信息,时间信息等等能够交给jvm。让他去存储。)

第二再把类文件所对应的的类文件class对象交给jvm,因为java万事万物都是对象,所有jvm他一定有一个东西去表示对象。

所以这些可以宏观的视为类加载器的装载过程。

2、类加载器工作原理

1、装载

(1).先找到类文件所在的位置

(2).类文件的信息交给jvm

(3).类文件所对应的的class对象交给jvm

这也是我们装载的过程,也就是我们背的类装载机制中第一个内容。就是我们看到图解的第一部分内容。

所以然后他就会进入接下来的链接和初始化;他的使用和卸载我们可以不用管他。

所以接下来第二步就是链接

2、链接

      他包含三部分:

  1. 验证
  2. 准备
  3. 解析

     下面我们会进行对其详细解释。

3、初始化

     下面我们会进行对其详细解释。

以上这三个就是类加载机制的的三个过程

这三步不是凭空想象,是根据官网得知的。

那么再往下走的话,思考一下,往下每一步如何去深究?

简单的来说:第一步我们是去寻找?那么我们该如何是进行寻找类的这一块内容?

实际上java是一个面向对象的开发语言。万物万事皆对象,如果我们要去找类。那么在java中有一个内置的对象可以帮我们去找类。

也就是类加载器classloader,更确切可以称之为类装载器,我们可以通过他来找到类。下面的先不管他。第一步我们就是先去加载去找类

如果我们是这个类装载器的一个设计者的话,我们该如何去设计他?

我们不可能直接通过这个类装载器classloader.find(类的全路径)直接去查找,因为这样他是无法去管理的。

如果我去设计的,我会对这些类去分门别类,怎么去分门别类呢?

我们认为不同的类装载器应该去装载不同区域的这样一个类。

怎么理解?说白的就是面试中常会被问到的这张图:

不同的装载器去装载不同目录下的类

比如说:Bootstrap是我们根的类装载器,他是装载我们系统中rt.jar包下所有的类。就是所谓不同的类去分工别类。然后依次往下,我们可以看到他们分别装载哪些目录下的类。

最下面的一个自定义的类装载器,我们可以根据自己定义按照我们自己的规则去进行相应的装载。

然后这个图我们看了就算了,那么他还有什么点是好聊的吗?

看了看,他还是有些点是可聊的;比如说:装载的机制我们可以来聊一下。

3、何为装载的机制:微观

装载的机制就是:我该如何进行装载

不就是不同装载器去装载不同目录下的吗?是,看似很假单

但他有一个问题是:当我们在存在同一个完全相同的类的全路径的时候。我该如何去进行装载呢?

也就是说我们jvm中不能存在类的全路径是一样的类了,不然我调用就会出错,比如:我们在系统下的rt.jar包有一个java.long.String这样一个类,那么此时我们自己也创建了一个相同的类。此时此刻就会出现问题了。你装载一个,我又去装载一个此时系统里就会有两全路径完全一个类,当被调用时就会有问题。所以我们要避免全路径名的不能存在两份。所以我们就需要一个机制,也就是说我们装载的时候就不能各干各的。那么怎么做呢?

就是假如说我们在自定义装载器想要去装载某一个类的时候,我自己先不装载,我先去问下我的父装载器,让你去装载,此时他也不装载,他就继续往上,让父节点去装载,同样他也不装载,就是继续往上。直到找到他的一个根节点让他先去优先去装载一下。看你能不能找到这个全路径的类。如果根节点说它找到了,怎么办,那么此时下面的这些子类就不用装载了。这样就确保我们jvm中只有这样一个全路径的类了。如果没有找到就直接往下,交给他直接的子节点,让他去找。如果他找到,下面同样不用找了。如果没有同理,继续往下去找。直到都没有找到,那就是我自己去装载了。这样就确保了这样一个唯一的全路径的类。

这个也就是我么常说的双亲委派模式

所以我们常说的双亲委派模式就是这个。这个加载我们就可以认为他是双亲委派。不需要弄的明明白白,我们只需要知道:

当我们自己某一个类装载器有一个类的装载请求的话,自己不会去优先装载。而是让顶层的这样一个哥们去装载。直到一层一层的装载不到,我在去进行装载,那么我们就能够去保证他就有一份。

那么这种装载机制我们是否能够去破坏他?

就是说java开发这都是好事之徒;肯定有人不想采用这个装载机制,他去按照自己的方式去实现。

因此就涉及到我们能够去破坏它?所以这也是面试中除了常会被问到的双亲委派常问题,另一大问题,

4、上面既然我们已经知道了啥是双亲委派了,那么怎么去破坏呢?

首先我得要想清楚的一个点就是:

jvm当中,我们jdk是如何实现这个双亲委派的?

我先把这个问题搞清楚之后;我才知道我如何把他去破坏;

我们根据他是如何实现的搞清楚之后,我们自然而然就知道怎么去破坏他。

假入我们是springboot的设计者的话?

我设计的方式就是我的这个类Bootstrap ClassLoader

一定是,有一个loader方法。这个方法里面有一个findParent()方法,就是我先去在我的parent,让他们去加载。如果他没有加载到,再让我自己去加载。

所以他一定会是有这样一段代码。他会去做这样一件事情。

也就是说我们想去破坏他的话,我们只需要去复写他这样一个方法就行了(源码是loadClass()方法;这个方法里面有一个parent.loadClass()去加载父类的方法,所以在此去重写这个方法可以做到)。这是我们可以想到一个思路,当然还有其他的方式:在我们线程层面也能去进行破坏。

至此,我们通过这种方式找到这个类之后呢?如果我们作为jvm的设计者,我们接下会去要怎么设计呢?

三、类加载机制分析

1、类加载

那么接下来是不是把找到的类去交给jvm去运行了。那么问题来了我怎去交呢?我难道要一下子把整个文件全部拿过来吗?这样也不合理,这样不符合我们一个的优秀。我们想要的优秀应该是将class当中的内容按照不同的类别去分门别类的去存储到我们jvm当中而不是将整个class中的数据全部都放到jvm(此时jvm看做一个整块的内存区域)当中。所以他要去做一个分门别类,那么怎么样去分门别类呢?

如果我是一个设计者的话,我会把jvm这个区域去做相应的划分。想一想是不是应该去划分,划分的目的不就是把class文件的信息去进行打散吗。就是我们类信息放哪?变量放哪?方法放哪?既然我们要去进行打散的话,是不是先要把类文件的信息交给jvm(装载的第二步)

在交给jvm的同时把类的信息相关信息存在jvm当中,那么我会有一个专业的方式去做,这个方式就是把对应的信息去放入对应的jvm区域当中。

1、那么何为对应的区域?

也就是把类文件字节码流放入静态存储结构。

2、为什么是静态存储结构?

原因是他是一个静止的文本流。这一块我们会放到jvm里面的某一块区域。

这个区域就是我们类的信息的存储的区域:Method Area.就是把我们类文件的信息放入这里面。这是第一点;

第二就是我们类的信息存放在这里面的,那么我们class文件对应的类对像我们该如何去存储?

那么我们认为在jvm当中应该也有一块区域去存储:称为我们一个堆。这就是我们常看到jvm运行时区的一个head:堆。

到这里我们已经划分出两块区域,肯定还有其他区域,暂时先不引出。

这两块区域也不是我们凭空捏造出来的。而是官网中有对应的说明。

我们从官网可知:方法区他不是存类的属性信息的等等,而是存的是类的,比如文件的创建时间,作者等等这些信息。

上面我们说对象信息他是存在堆里面的,是这样的吗?我们看他官网,继续看:他说堆存的是all class。所以不用说了。

再往下看:那么类加载器中的这个链接呢?

2、链接

1、验证

链接首先就是验证我们的类文件:我们看首先他是怎么验证呢?

保证被加载类的正确性。就是类的格式是不是正确,元数据是不是正确,字节码是不是正确等等。

2、准备

那么链接的第二个阶段是准备;那么何为准备?

重点记住:要为类的静态变量分配内存空间,并将其的值初始化默认值(记住)

比如说:我们class文件有一个静态变量;static int a=10;那么此时到了链接阶段中的准备阶段,他就会为这个静态变量去分配对应的内存空间,然后给这个值默认出化为0.这就是准备阶段需要做的事情。

3、解析

那么何为解析呢?

解析的阶段就是将类中的符号引用转换为直接引用。

那么符号引用和直接引用是什么?我们要去推敲,不然只是记忆,没法有理可据。

符号引用应该讲的就是我们class file format里面的信息,

这些就是我们的符号引用,符号引用是因为我们class文件里面存的还是这个状态,这个class文件格式的规范,只是一个符号的表示,跟我们的内存没有关系(存储在jvm什么地方),他只是说你在我class文件里面叫什么,那么这些符号引用到了内存当中我要把他编变成直接引用。这就是说明了原来我在class中代表的是String str[ace0 flag]=这样一个地址或符号,那么它就是对应j内存中某一个真实的地址指向了;就是说在class文件他只是一个代称,class能认识就行了,那么现在到真正内存中了,你就要被别调用被赋值了嘛,就是需要真正的某个地址了嘛(简单说把符号转化为内存需要引用的内存地址)。

所以我要做的的事情就是他这个符号引用转化为直接引用。

这个直接引用就是我们在java当中能看到的地址,说白了就是String str= 这个str它所对应的真实的地址是什么。

除此之外,解析还有其他内容,如官网介绍:第 5 章.加载、链接和初始化 (oracle.com)

比如:类与接口解析,接口方法解析,方法类型和方法句柄解析,字段分辨率解析等等

 除了上面上面三个检验步骤,他还有另外两个:可自行查看官网

4、访问控制

5、覆盖

3、何为初始化?

是为静态变量初始化真正的值。上面那个a就会真正的被赋值为a=10.

至此我们Person类就经过我们类加载机制了,现在已经到达了jvm.

那么如我们是jvm设计者,jvm这个快区域需要怎么设计呢?我们前面已经讲到,他已经分出了两块区域了

我们走到这里看到的结果就是看到我们类的信息和堆的信息分别再两块内存当中。

如果我认为我这jvm这一块区域的设计者的话,这个地方我该如何设计?

我们看官网,他的运行时数据区不仅上面分的两块:

所以接下来就是看看他这一块的运行时数据区。

四、运行时数据区

在装载阶段的第(2),(3)步可以发现有运行时数据,堆,方法区等名词

(2)将这个字节流所代表的静态存储结构转化为方法区的运行时数据结构

(3)在Java堆中生成一个代表这个类的java.lang.Class对象,作为对方法区中这些数据的访问入口 说白了就是类文件被类装载器装载进来之后,类中的内容(比如变量,常量,方法,对象等这些数 据得要有个去处,也就是要存储起来,存储的位置肯定是在JVM中有对应的空间) 

这个运行时方法区不仅涉及到上面这两块,他还有其他四个区域。所以这个时候我们就来到了运行时数据区。如官网:第 2 章。Java 虚拟机的结构 (oracle.com)

那么我们应该先看哪一个呢?

关于方法区和堆我们已经讲过他的来通去脉,所以接下来我们先看剩下的几个

1、运行时常量池

根据官网来看:我们会看到一句话:每一个运行时常量池是从java虚拟机的方法区所去进行分配的,这是jdk8版本的官网描述。

我们按照这句话来理解的话,运行时常量池应该是在我们的方法区里面。

就变成了这样了

我们根据官网看他还有两个管stacks栈的描述:

2、虚拟机stacks

它是一种数据结构,这种数据结构他有一个特点就是:先进后出,或者后进先出。

这个东西是干嘛的呢?

我是这么来理解的:jvm的一个设计者他认为,我们类的信息存在我们的方法区了,我们类的常量也存在这里面了,我们对照我们类文件去看,这里面我们该存的都存了,这是不是除了存储一些数据的话,是不是还要存储其他数据或者他的灵魂,这里面的灵魂是应该是他方法的执行,或者说java每一个线程去调用方法去执行才是进程间的灵魂。不执行方法的话我们这个还有什么么意义呢?

那么方法的执行与否,方法被线程调用与否的话,这种关系在我们的运行时数据区,如果你仅仅是一个存储的结构的话,好像不能够去表示。既然这样,我去设计一个栈出来。这个栈呢就代表是一个线程。是要去表示一个方法的执行的话没我就设计一个栈。线程中每一个方法就是我们这个栈里面存储的元素了。就是有一个方法被执行了就把方法压入栈里面,又有一个方法就在把这个方法压入栈里面。依次往下。然后有一个方法被执行完,他就去出栈,执行完就是出栈,

所以从这里面我们可以去感受到 ,为什么会有一个栈的设计。

实际上他解决的问题应该是:线程执行方法的表示

这是我们简单的一个了解,先不去深入。

那么为题来了?具体是这样的吗?

我们看官网:说每一个java线程都有一个java虚拟机栈,他的创建时机,就是在这个线程被创建的时候就会去创建一个虚拟机栈。他的每一个栈存的就是我们方法执行。

所以在我么jvm内存分布中又多了一快区域:java虚拟机栈

所以我们认为这个是能够理解的。此时我们会有一个不经意的想法:就是如果我们java 方法是基于java虚拟机栈去表示的,如果我java去调用c语言代码的话,那么我是不是也应该有一个类似于虚拟机栈呢?这就是我们所说的native method stacks本地方法栈

3、本地方法栈

根据官网可知:本地方法栈就是调用C语言的这个栈。C语言实现的栈策存储结构就跟java实现方式是差不多的。他就可以类比我们java虚拟机栈去学习。

如果说现在我们有两个线程,这两个线程都有各自的java虚拟机栈,那每一个线程都会去调用方法的话,那么这个栈针就会去相应的去压栈。当这两个线程不断去调用方法,就会不断的去压栈。此时就会出现一个问题:

因为此时我们会有一个大大的cpu给我们每一个线程一个相应的资源,会有一个相应的执行权,当我们cpu执行到了虚拟机栈的A栈针(方法)的地方之后,此时失去了执行调度,我就会去执行另一个虚拟机栈,当我们第一个虚拟机栈再次获取一个调度执行权的时候,我是不是还需要从A栈针这个地方去继续执行。如果我要去继续从这个地方去执行,那么我就要去保存记录我刚刚失去cpu资源方法所执行的这个地方。

所以在整个运行时数据区中他应还有一个数据区域,代表着记录每一个线程继续执行方法所在的位置。这就是我们所说的 the pc register

4、寄存器pcthe pc register

何为 the pc register?我们看官网就知道:一个java进程可以支持非常多的java线程,每一个java线程都有一个自己独立的一个pc register,他的作用是什么?他是为了进行记录当前方法正在执行所在的这样一个位置。那么这个时候我们就认为这个就有存在的必要了。

这样就可以把我们看到的六块区域划分为5块区域。

到这里我们就对整体有了一个认知。

五、总结

所以总结他整个流程图就是这样的:

值得说明的

(1)方法区在JDK 8中就是Metaspace,在JDK6或7中就是Perm Space

(2)Run-Time Constant Pool

Class文件中除了有类的版本、字段、方法、接口等描述信息外,还有一项信息就是常量池,用于存放编译时期生成的各种字面量和符号引用,这部分内容将在类加载后进入方法区的运行时常量池中存放。

Each run-time constant pool is allocated from the Java Virtual Machine's method

area (§2.5.4).s 

至此我们java 类如何到jvm的我们已经聊完了。现在我们就可以去真正的聊聊jvm这里面的东西了。

六、详聊运行时数据区

那么我们有必要去详聊吗?那么详聊什么?

这就是我们详聊的运行时数据区。但是我还是有点忐忑。为什么?

因为我们要学习jvm到底要学习什么呢?

我认为上面这张图是需要学习的,当我们把这张图学完之后,我们把数据不断的往里面去放,就会有内存空间不断的去使用,不够用的时候我就会去形成去做回收。那么我们就要去垃圾回收机制,垃圾回收机制这时候就要对应的就是看垃圾回收算法。就要有对应的垃圾收集器。

那么怎么回收?怎么去看我们垃圾回收日志?这不就我们需要学习jvm的内容的吗?

所以我们现在慢慢来,慢慢的往下推:

那么我们先想象,我们到底应该先看哪一个呢?

我们看左上角的方法区好像可以值得探究:

根据官网来看:首先看运行时数据区的讲解,是说有些数据区是根我们jvm一个生面周期的,随着jvm的创建而创建,销毁而销毁。有些是根据线程一个额生面周期的。所以这就涉及到了线程的安全性和不安全性问题。

那么我先来看方法区:

1、方法区(Meathod Area)

我们之前认知或者说对于方法区的一个理解来说;只保留在他保存类的这样一个信息,是在装载阶段的第二个阶段。

1、首先我们会看到一点是(生命周期):每一个java虚拟机只有一个方法区,而这一个方法区是被所有的线程去共享的。

从而我们得到的结论就是:方法区只有一个,线程共享的内存区域, 也就是【线程非安全】,生命周期是跟虚拟机一样的。

这就是我们而根据官网一句话得出来的结论。

2、然后继续看官网第二句描述;说方法区所存储的就是:类信息、常量、静态变量、还有及时编译器编译之后的代码。

所以我们就看到,除了类型信息,他的常量,静态变量也是存在里面的。

3、在继续往先看看官网,说方法区逻辑上是属于堆的一部分,然后垃圾回收不太会去讨论方法区的垃圾回收,虽然他也会存在垃圾回收,但是一般情况下,垃圾回收不会去讨论这块区域。

4、继续往下看说,当我们这些信息继续往方法区中去存,当他不够存了,他就会抱一个内存溢出的错误。

我们从上面来接可以清楚就从官网了解就可以知道他的一些特性。现在我们而对方法区有一个了解之后我们在去看堆这样一个信息。

2、堆(heap)

那么何为堆?

根据官网介绍。

1、首先第一句说:堆也是所有线程共享的。说白的就是堆只有一个,线程共享的内存区域, 也就是【线程非安全】,生命周期是跟虚拟机一样的。

2、第二句话:也就是说它存储我们的class对象或数据会在这里面去进行分配。

3、再往下看,也会看到当他的内存不够了,他也会发生一个oom内存溢出。

所以的我们oom不仅是我们堆内存会发生,我们的方法区也会发生,

然后我们就此了结之后再往下看,我们在往下看发现就是线程私有的了

3、Java虚拟机栈

这一个就比较好理解,他就是来存储线程所对应的的栈,然后栈里面去存储我们的栈针吗。

那么比如说我有一个方法在调用执行,那么该怎么去表示呢?

假如说,我a方法调用b方法,b方法调用c方法,。那么此时此刻我们该怎么去用栈表示呢?

如图所示:

就是说我们有一个线程现在去调用a,当a没有执行完,他又去调用b了,此时b就会去进行压栈。b又去调用c了。b又会去进行压栈。当着一流程被调用完之后,就会去依次出栈。c执行完,出栈,b去执行,b执行完,a去执行,直到结束。

这就是我们看到java虚拟机栈的一个表现形式。

那么如果说我们去递归调用方法,当我们的栈的深度不够用了的时候,就会报:Stack Overflow。这就是我们看到关于栈匿出的这块情况。

然后我么在继续看,上面运行时数据区的途图中还有什么可以探讨的呢?

我们发现还有两个区域,发现这两个区域就没有什么好研讨的了,

一个是本地方法栈,他是调用c语言的,还有程序计数器,他其实跟我们java开发层面没有太大关系,所以我们了解他是干嘛的就行了。

4、总结

一个线程的创建代表的是一个栈。每一个方法被当前线程调用了,就代表一个栈针。

七、聊聊官网没有介绍的

这些也是我们面试中常会被问到的一下东西;

1、方法区

像方法区里面有一个我们不知道的知识点,而且是常聊的一个e东西:

1.7Jdk(及之前): PermSpace-------永久代

1.8Jdk(及以后) MetaSpace -------元空间

这一块其实并没有什么技术含量,我们只要知道,作为一个了解就可以了,

2、运行时数据区与内存模型

还有一个跟我们面试题相关联的就是:

大家所看到的jvm的运行时数据区,有一个地方我们难免会有一个想法就是运行时数据区和内存模型他们之间的关联是什么?

因为在我们的内存模型也会去讨论我们的一个堆,以及PermSpace和MetaSpace 等。

而这时候我们怎么样去理解呢?

既然有了运行时数据区,那么内存模型【JMM】又是什么?

我们可以这样去理解:

运行时数据区官网对他的一个描述其实是很清晰的:他表述的我们各种数据的一个运行时的状态,也就是说你程序执行的时候,你的数据在jvm中的他的一个运行时的一个状态。总的就是代码运行时的状态。

而所谓的一个java的内存模型,或者所谓的JMM则表示他实际的物理落地的内容也就是说当我代码不在运行的时候,我此时此刻又是一种什么样的形式区存在?

那么我们就可以把它按照内存模型去划分。

再者说:我们可以这样认为运行时数据区他是jvm层面的事情。而内存模型他是java层面的事情。我们一般去讨论内存模型,一般是去讨论线程的安全与否,因为他去讨论内存模型的话,你会拿主内存和我们的一个工作内存去做一个对比。而这个内存模型真实会把哪两块去拿出来?

就是我们运行数据区中左边共享的两块会拿出来探讨

所以我们会把内存模型区划分左边的一个MetaSpace ,和右边的这样的一个堆内存。我们可以做这样的一个对应。

这是这两者之间的关系,如果你非要把他们之间进行关联的话,上面这个是我们的JMM内存模型,那么其实我们可以看到他是这样对应的

但是一个是表示运行的一个状态,一个是运行后落地的一个额状态。

那么我们为什么不去讨论线程私有的区域呢?

因为线程私有的相对的生命周期都比较短,我们不会再内存模型去做进一步的探讨。

然后回顾一下,我们上面没有细聊的有哪一块,我们发现堆和方法区都做了详细的探讨,或者后面会花大量时间去探讨,所以就发现虚拟机栈没有太多的探讨。只是看了方法的压栈过程

所以接下来我们会去探讨:

3、java虚拟机栈,执行方法的时候,到底经历了什么?

这就涉及到我们平时对java class文件进行反编译的时候,看到的字节码指令,这字节码指令就对应java虚拟机栈执行的过程。

那么怎么去理解?

我们查看class文件的方式除了查看16进制的方式还可以进行javap- c class文件进行查看class文件的方式。

然后我们打开看,他就是一个字节码指令。

那么何为字节码指令,坦白的说:他描述的你这个类文件他在虚拟机当中他的这样一个每一步的一个状态是干嘛的。

这个字节码指令我们看不懂,但是有人能看懂,那就是jvm官方文档。爪哇SE规范 (oracle.com)

JVM-java对象内存分布(二)_平凡之路无尽路的博客-CSDN博客

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/684664.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【设计模式】工厂模式(简单工厂模式、工厂方法模式、抽象工厂模式)详记

注:本文仅供学习参考,如有错漏还请指正! 参考文献/文章地址: https://zh.wikipedia.org/wiki/%E8%AE%BE%E8%AE%A1%E6%A8%A1%E5%BC%8F%EF%BC%9A%E5%8F%AF%E5%A4%8D%E7%94%A8%E9%9D%A2%E5%90%91%E5%AF%B9%E8%B1%A1%E8%BD%AF%E4%BB%B…

第20章:MySQL索引失效案例

1.全值匹配我最爱 当SQL查询 EXPLAIN SELECT SQL_NO_CACHE * FROM student WHERE age30 AND classId4 AND NAMEabcd; 创建3个索引 idx_age,idx_age_classid,idx_age_classid_name 当前优化器会选择跟where条件匹配最高的idx_age_classid_name索引,直接查询出对…

[CVPR 2023] Imagic:使用扩散模型进行基于文本的真实图像编辑

[CVPR 2023] Imagic:使用扩散模型进行基于文本的真实图像编辑 Paper Title: Imagic: Text-Based Real Image Editing with Diffusion Models The first author performed this work as an intern at Google Research. Project page: https://imagic-editing.github.io/. 原文…

登出成功后token过期方案

目录 需求分析解决方案实现步骤登出成功相关逻辑改造携带token请求相关逻辑需求分析 登录成功后,系统会返回一个token给客户端使用,token可以用来获取登录后的一些资源或者进行一些操作。当用户在系统中注销或者退出登录时,需要对token进行过期处理,以保证系统的安全性和数…

校园网WiFi IPv6免流上网

ipv6的介绍 IPv6是国际协议的最新版本,用它来取代IPv4主要是为了解决IPv4网络地址枯竭的问题,也在其他很多方面对IPv4有所改进,比如网络的速度和安全性。 IPv4是一个32位的地址,随着用户的增加在2011年国家报道说IPv4的网络地址即…

基于前后端交互的论坛系统(课设高分必过)

目录 前言概述 一.前期准备 项目演示 用户注册 用户登录 主页面 发帖页面 个人信息及修改 用户主帖 站内信 需求分析 技术选型 二.建表分析 三.环境搭建 技术环境的检查与安装 检查JDK ​编辑 检查数据库 检查Maven 检查git ​编辑 项目启动的通用配置 新…

【系统架构】第五章-软件工程基础知识(需求工程和系统分析与设计)

软考-系统架构设计师知识点提炼-系统架构设计师教程(第2版) 需求工程 软件需求3个层次: 业务需求:反映了组织机构或客户对系统、产品高层次的目标要求用户需求:描述了用户使用产品必须要完成的任务,是用户…

rust abc(3): 布尔和字符类型的使用并与C/C++对比

文章目录 1. 目的2. 布尔类型2.1 只能赋值为小写的 true, false2.2 不能把数字赋值给bool类型变量2.3 正确写法汇总 3. 字符类型3.1 UTF-8 编码3.2 字符的意思是单个字符,多个字符不能用单引号 4. 总结 1. 目的 继续熟悉 rust 语言的基本数据类型, 感受 rust 编译期…

Redis【实战篇】---- 短信登录

Redis【实战篇】---- 短信登录 1. 导入黑马点评项目1. 导入SQL2. 有关当前模型3. 导入后端项目4. 导入前端项目5. 运行前端项目 2. 基于Session实现登录流程3. 实现发送短信验证码功能4. 实现登录拦截功能5. 隐藏用户敏感信息6. session共享问题7. Redis代替session业务1. 设计…

Spark10-11

10. 广播变量 10.1 广播变量的使用场景 在很多计算场景,经常会遇到两个RDD进行JOIN,如果一个RDD对应的数据比较大,一个RDD对应的数据比较小,如果使用JOIN,那么会shuffle,导致效率变低。广播变量就是将相对…

【C/C++】使用类和对象 练习EasyX图形库

创作不易&#xff0c;本篇文章如果帮助到了你&#xff0c;还请点赞 关注支持一下♡>&#x16966;<)!! 主页专栏有更多知识&#xff0c;如有疑问欢迎大家指正讨论&#xff0c;共同进步&#xff01; &#x1f525;c系列专栏&#xff1a;C/C零基础到精通 &#x1f525; 给大…

【关联式容器】之map和set

【关联式容器】之map和set 容器类型树形结构的关联式容器mapset&#xff0c;multiset&#xff0c;multimap的区别与联系 容器类型 在STL中&#xff0c;我们接触过许多容器&#xff0c;例如&#xff1a;vector&#xff0c;list&#xff0c;stack&#xff0c;queue&#xff0c;m…

conll2003数据集下载与预处理

CoNLL-2003 数据集包括 1,393 篇英文新闻文章和 909 篇德文新闻文章。我们将查看英文数据。 1. 下载CoNLL-2003数据集 https://data.deepai.org/conll2003.zip 下载后解压你会发现有如下文件。 打开train.txt文件&#xff0c; 你会发现如下内容。 CoNLL-2003 数据文件包含由单…

逍遥自在学C语言 | 指针陷阱-空指针与野指针

前言 在C语言中&#xff0c;指针是一种非常强大和灵活的工具&#xff0c;但同时也容易引发一些问题&#xff0c;其中包括空指针和野指针。 本文将带你了解这两个概念的含义、产生原因以及如何避免它们所导致的问题。 一、人物简介 第一位闪亮登场&#xff0c;有请今后会一直…

【玩转Docker小鲸鱼叭】理解DockerFile如此简单

DockerFile构建过程 DockerFile 是Docker的一个配置文件&#xff0c;本质上来说它只是一个文本文件&#xff0c;它是用来构建Docker镜像的。DockerFile配置文件中包含了一系列的指令和配置信息&#xff0c;用于描述如何构建镜像以及如何运行容器。通过编写 Dockerfile&#xf…

RISC-V处理器的设计与实现(二)—— CPU框架设计

前面我们选好了要实现的指令集&#xff0c;并且了解了每个指令的功能&#xff08;传送门&#xff1a;RISC-V处理器的设计与实现&#xff08;一&#xff09;—— 基本指令集_Patarw_Li的博客-CSDN博客&#xff09;&#xff0c;接下来我们就可以开始设计cpu了。当然我们不可能一上…

ChatGPT更新的使用指南,与其他类似的人工智能的软件和服务-更新版(2023-6-25)

文章目录 一、什么是ChatGPT二、如何使用三、如何使用ChatGPT帮助我们的工作和生活四、高阶用法1、角色扮演2、英语口语老师3、在搜索引擎中集成ChatGPT 五、常见问题五、其他类似的软件和服务 如果你还不知道如何注册和使用&#xff0c;可看末尾&#xff0c;手把手教你。 一、…

Linux线程同步

同步的几种方式&#xff1a;信号量&#xff0c;互斥锁&#xff0c;条件变量&#xff0c;读写锁 同步&#xff1a;对程序的执行过程进行控制&#xff0c;保证对临界资源的访问同一时刻只能有一个进程或线程访问。 2.1信号量 存在P操作&#xff1a;获取资源&#xff0c;信号量…

58.最后一个单词的长度

LeetCode-58.最后一个单词的长度 1、题目描述2、解题思路3、代码实现4、解题记录 1、题目描述 题目描述&#xff1a; 给你一个字符串 s&#xff0c;由若干单词组成&#xff0c;单词前后用一些空格字符隔开。返回字符串中 最后一个 单词的长度。 单词 是指仅由字母组成、不包含任…

通讯录获取APP程序分析

前言 APP非法获取用户通讯录等隐私信息 我用技术分析APP是如何获取信息的 如果你不幸中招了&#xff0c;可以参考下方链接(有偿) 我的方法是替换掉通讯录数据&#xff0c;替换不成功包退&#xff01; 每日16:00-06:00在线&#xff0c;5分钟受理&#xff0c;2~3小时完成 点下面…