首页 快讯正文

欧博代理:【JVM故事】领会JVM的结构,幸亏面试时吹牛

admin 快讯 2020-06-11 69 1


class文件花样



参考上一篇文章《【JVM故事】一个Java字节码文件的诞生记》,后续还会专门解说class文件的内部结构。


数据类型


jvm包罗两种数据类型,基本类型和引用类型。

基本类型包罗,数值类型,boolean类型,和returnAddress类型。

数值类型包罗,整型,浮点型,和char类型。

boolean类型同样只有true和false。

returnAddress类型是一个指针,指向jvm指令的操作码,在Java中没有与之对应的类型。

boolean类型的操作会被转化为int类型的操作举行,boolean数组会当成byte数组去操作。1示意true,0示意false。

引用类型包罗三种,类类型,数组类型,和接口类型。

它们的值是动态建立的类实例,数组,或实现接口的类实例。

数组有component类型和element类型,component类型就是数组去掉最外层维度后剩下的类型,可能照样一个数组类型(对于多维数组)。

element类型就是数组内里存储的最小数据的类型,它必须是一个基本类型,类类型,或接口类型。

对于一维数组的话,component类型和element类型是相同的。

引用类型另有一个特殊值,就是null,示意没有引用任何工具。


运行时公有数据区




jvm有一个堆,在所有jvm线程间共享,堆是一个运行时数据区域,所有为类实例和数组分配的内存都来自于它。

堆在jvm启动时建立,堆中工具不用显式释放,gc会帮我们释放并接纳内存。

方式区

jvm有一个方式区,在所有jvm线程间共享,它存储每一个类的结构。

像运行时常量池,字段和方式数据,方式和组织函数的代码,另有特殊的方式用于类和实例的初始化,以及接口的初始化。

方式区在jvm启动时建立,虽然方式区在逻辑上是堆的一部门。

但简朴实现时可以选择不举行gc和压缩,本规范没有强制要求方式区的位置,也没有要求治理已编译代码的计谋。

运行时常量池

运行时常量池就是类或接口的字节码文件里的常量池的运行时示意形式,它包罗几种常量。

如在编译时就已经知道的数字字面量值,和必须在运行时剖析的方式和字段的引用,运行时常量池的功效类似于传统语言的符号表,不外它包罗的数据会加倍宽泛。

运行时常量池分配在jvm的方式区,类或接口的运行时常量池在类或接口被jvm建立时才会构建。


运行时私有数据区


pc寄存器

jvm支持一次运行多个线程,每个线程都有自己的pc寄存器,任何时候一个线程只能运行一个方式的代码。

若是方式不是native的,pc寄存器包罗当前正在被执行的jvm指令地址,若是方式是native的,pc寄存器的值是未定义的。

jvm栈

每一个jvm线程都有一个私有的jvm栈,随着线程的建立而建立,栈中存储的是帧。

jvm栈和传统语言如C的栈相似,保留局部变量和部门计算效果,介入方式的挪用和返回。jvm栈主要用于帧的出栈和入栈,除此之外没有其它操作,

帧可能是在堆上分配的,以是jvm栈使用的内存不必是延续的。

native方式栈

native方式不是用Java语言写的,为了支持它需要使用传统栈,如C语言栈。不外jvm不能加载native方式,以是也不需要提供native方式需要的栈。





每次当一个方式被挪用时一个新的帧会被建立。当方式挪用完成时,与之对应的帧会被销毁,无论是正常完成照样抛异常竣事。

以是帧是方式挪用的详细体现形式,或称方式挪用是以帧的形式举行的。帧用来存储数据和部门计算效果,和执行动态链接,方式返回值,分发异常。

帧分配在建立帧的线程的jvm栈上,每一个帧都有自己的内陆变量数组,自己的操作数据栈,和一个对当前方式所在类的运行时常量池的引用。

内陆变量数组和操作数栈的巨细在编译时就确定了,它们随着和帧关联的方式编译后的代码一起被提供,因此帧这种数据结构的巨细只依赖于jvm的实现,这些结构所需的内存可以在方式挪用时同时被分配。

在一个线程执行的任何时刻,都只会有一个帧是处于激活的。这个帧被称为当前帧,与之对应的方式被称为当前方式,方式所在的类被称为当前类,此时用到的内陆变量数组和操作数栈也都是当前帧的。

一个帧将不在继续是当前帧,若是它的方式挪用了另一个方式,或者它的方式竣事了。

当一个方式被挪用,一个新的帧被建立,当执行控制由原来的方式通报到新的方式时,这个新的帧变为当前帧。

当方式返回时,当前帧把方式执行的效果传回到上一帧,当上一帧被激活的同时当前帧会被抛弃。

内陆变量数组

每一帧都包罗一个变量数组,就是都熟知的内陆变量存储的地方。这个内陆变量数组的长度在编译时确定,随着编译后的方式代码一起提供。

通常一个内陆变量(的位置)能够存储一个类型的值,然则long和double类型却需要两个内陆变量(的位置)才气存一个值。

内陆变量按索引寻址,第一个内陆变量的索引是0。long和double需要消耗两个延续的索引,但却是凭据较小的这个索引寻址的。不能凭据较大的谁人索引去读数据,然则可以写入,固然这样将使内陆变量内容庞杂。

在方式被挪用时,jvm使用内陆变量来吸收通报进来的参数值。在类(静态)方式挪用时,所有参数被传入从索引0最先的连贯的内陆变量数组里。

在实例(非静态)方式挪用时,索引0处总是传入正在其上执行方式挪用的谁人工具的引用,(就是Java中的this了),所有参数被传入从1最先的连贯的内陆变量数组里。

操作数栈

每个帧包罗一个后进先出的栈,用于存储正在执行的jvm指令的操作数,就是都熟知的操作数栈,这个栈的最大深度在编译时就已确定,随着编译后的方式代码一起提供。

当帧被建立时,操作数栈是空的,jvm提供一些指令用于加载常量值,内陆变量值,字段值到操作数栈上,另一些jvm指令接纳操作数栈上的操作数举行操作,并把效果放回到操作数栈上。

操作数栈也用于准备将要通报给方式挪用的参数和吸收方式挪用返回的效果。

long和double类型的值占用两个单元的栈深度,其它类型的值占用一个单元的栈深度。

动态链接

每一个帧都包罗了对当前方式所属类型的运行时常量池的引用。目的是为了支持方式代码的动态链接。class文件中形貌一个方式引用被挪用的方式和被接见的变量的代码,是接纳符号引用的形式实现的。

符号引用的形式可以大略的认为是字符串的形式,就是用字符串标明需要挪用哪个类的哪个方式或接见哪个字段或变量。就像符号引用这个名字一样,这些仅仅是符号,是拿不到详细值的,以是必须要举行转换。

动态链接就是把这些符号方式引用转换为详细的方式引用,在必要时加载类来剖析尚未明确的符号,把符号变量的接见转换为这些变量运行时所在存储结构的适合的偏移量(索引)。这样的方式又称为后期绑定。

方式挪用

一个方式挪用正常完成(即没有抛异常)时,会凭据所返回的值的类型执行一个适合的return指令,当前帧会去恢复挪用者的状态,包罗它的内陆变量和操作数栈,使挪用者的程序计数器适合的递增来跳过刚刚的谁人方式挪用指令。

返回值会被放到挪用者帧的操作数栈上,然后继续执行挪用者方式的帧。

一个方式在挪用时抛出了异常,且这个异常没有在这个方式内被捕捉处置,将会导致这个方式挪用的突然竣事,这种情况下永远不会向方式的挪用者返回一个值。


特殊方式


站在jvm的级别,每一个用Java写的组织函数都以一个实例初始化方式泛起,且都是特殊的名字,就是<init>,这个名字是编译器提供的。

实例初始化方式只能在jvm内部使用invokespecial这个指令挪用,且只能在尚未初始化的类实例上挪用。

一个类或接口最多可以有一个类或接口初始化方式,通过挪用这个方式被初始化。类或接口的初始化方式也有特殊的名字,就是<clinit>,该方式没有参数,且返回值是void。

方式名称也是由编译器提供的,从Java7最先,在字节码中这个方式必须被标记为静态的才行。

这个初始化方式是被jvm隐式挪用的,它们绝对不会直接被用任何jvm指令挪用,仅作为类初始化历程的一部门被间接的挪用。


Java类库


jvm必须为Java类库的实现提供足够的支持。一些类库中的类若是没有jvm协助是无法实现的。

反射,就是在运行时获取某个类的类型相关信息,如它的字段信息,方式信息,组织函数信息,父类信息,实现的接口信息。

这些信息都必须是把一个类加载完之后才可以知道的,只有jvm才可以加载类。如java.lang.reflect这个包下的类和Class这个类。

在Java中加载一个类或接口用类加载器,即ClassLoader,背后照样委托给jvm来实现的。

链接和初始化一个类或接口。

平安,如java.security包下的类,另有其它类像SecurityManager。

多线程,如线程这个类Thread。

弱引用,像java.lang.ref包下的类。


公有设计,私有实现


以上内容只是jvm的一个“相对宽泛”的规范,它并不是实现方案,也不是实现细节。

实现者可以凭据自身的需要来实现jvm,如运行在后端服务器上的jvm和运行在移动装备上的jvm一定侧重点有所不同。

从事Java的人都知道,事实上jvm是有较多的实现版本。

由于jvm是处在Java语言和操作系统之间的,以是它要向上提供对Java的支持,向下与操作系统优越交互。


写在最后


高级语言(Java,C#)中的许多操作如文件操作,网络操作,内存操作,线程操作,I/O操作等,都不是高级语言自身能够实现的。

也不是它们的虚拟机(JVM,CLR)能够实现的,现实最终是由操作系统实现的,由于这些都是系统资源,只有操作系统才有权限接见。

若是你用Java或C#代码建立了一个文件,万万不要以为是Java或C#建立了这个文件,它们只是层层向下挪用了操作系统的API,然后到文件系统API,最后可能到磁盘驱动程序。

由此可以看出,要想设计一门语言,不单单是关键字、语法、编译器,类库,虚拟机这些,还要深度领会操作系统,甚至是硬件,如CPU架构和CPU指令集等。

以是,和语言相关的事情,每一项都是异常的繁琐庞大,都需要投入大量的人力、财力、时间去研究,最后纵然研究乐成了,可能没有生态,没人使用,自然也无法赚钱。

因此,国人现在还没有一门属于自己的真正语言。

>>> 热门文章集锦 <<<

 

结业10年,我有话说

【面试】我是若何面试别人List相关知识的,深度有点长文

我是若何在结业不久只用1年就升为开发组长的

爸爸又给Spring MVC生了个弟弟叫Spring WebFlux

【面试】我是若何在面试别人Spring事务时“套路”对方的

【面试】Spring事务面试考点吐血整理(建议珍藏)

【面试】我是若何在面试别人Redis相关知识时“软怼”他的

【面试】吃透了这些Redis知识点,面试官一定以为你很NB(干货 | 建议珍藏)

【面试】若是你这样回覆“什么是线程平安”,面试官都会对你另眼相看(建议珍藏)

【面试】迄今为止把同步/异步/壅闭/非壅闭/BIO/NIO/AIO讲的这么清晰的好文章(快快珍藏)

【面试】一篇文章帮你彻底搞清晰“I/O多路复用”和“异步I/O”的宿世今生(深度好文,建议珍藏)

【面试】若是把线程看成一个人来看待,所有问题都瞬间明了了

Java多线程通关———基础知识挑战

品Spring:帝国的基石

 

作者是事情跨越10年的码农,现在任架构师。喜欢研究手艺,崇尚简朴快乐。追求以通俗易懂的语言解说手艺,希望所有的读者都能看懂并记着。下面是民众号的二维码,迎接关注!

 

,

Allbet

www.10-10-10-1.com欢迎进入欧博平台(Allbet Gaming),欧博平台开放欧博(Allbet)开户、欧博(Allbet)代理开户、欧博(Allbet)电脑客户端、欧博(Allbet)APP下载等业务。

版权声明

本文仅代表作者观点,
不代表本站欧博网址的立场。
本文系作者授权发表,未经许可,不得转载。