58 - ASM之JVM Architecture

JVM的组成部分

从JVM组成的角度来说,它由Class Loader SubSystem、Runtime Data Areas和Execution Engine三个部分组成:

  • 类加载子系统(Class Loader SubSystem),负责加载具体的.class文件。
  • 运行时数据区(Runtime Data Areas),主要负责为执行引擎(Execution Engine)提供“空间维度”的支持,为类(Class)、对象实例(object instance)、局部变量(local variable)提供存储空间。
  • 执行引擎(Execution Engine),主要负责方法体里的instruction内容,它是JVM的核心部分。
jvm architecture

在JVM当中,数据类型分成primitive type和reference type两种,那么ClassLoader负责加载哪些类型呢?

  • 对于primitive type是JVM内置的类型,不需要ClassLoader加载。
  • 对于reference type来说,它又分成类(class types)、接口(interface types)和数组(array types)三种子类型。
    • ClassLoader只负责加载类(class types)和接口(interface types)。
    • JVM内部会帮助我们创建数组(array types)。

JVM Execution Engine

At the core of any Java Virtual Machine implementation is its execution engine.

JVM文档:指令集

In the Java Virtual Machine specification, the behavior of the execution engine is defined in terms of an instruction set.

执行引擎:三种解读

The term “execution engine” can also be used in any of three senses: an abstract specification, a concrete implementation, or a runtime instance.

  • The abstract specification defines the behavior of an execution engine in terms of the instruction set.
  • Concrete implementations, which may use a variety of techniques, are either software, hardware, or a combination of both.
  • A runtime instance of an execution engine is a thread.

Each thread of a running Java application is a distinct instance of the virtual machine’s execution engine. From the beginning of its lifetime to the end, a thread is either executing bytecodes or native methods. A thread may execute bytecodes directly, by interpreting or executing natively in silicon, or indirectly, by just-in-time compiling and executing the resulting native code.

A Java Virtual Machine implementation may use other threads invisible to the running application, such as a thread that performs garbage collection. Such threads need not be “instances” of the implementation’s execution engine. All threads that belong to the running application, however, are execution engines in action.

Runtime Data Areas: JVM Stack

在现实生活当中,我们生活在一个三维的空间,在这个空间维度里,可以确定一个事物的具体位置;同时,也有一个时间维度,随着时间的流逝,这个事物的状态也会发生变化。简单来说,对于一个具体事物,空间维度上就是看它占据一个什么位置,时间维度上就看它如何发生变化。 接下来,我们把“空间维度”和“时间维度”的视角带入到JVM当中。

在JVM当中,是怎么体现“空间维度”视角和“时间维度”两个视角的呢?

  • 时间维度。上面谈到执行引擎(Execution Engine),一条一条的执行instruction的内容,会引起相应事物的状态发生变化,这就是“时间维度”的视角。
  • 空间维度。接下来要讲的JVM Stack和Stack Frame,它们都是运行时数据区(Runtime Data Areas)具体的内存空间分配,用于存储相应的数据,这就是“空间维度”视角。

thread对应于JVM Stack

上面提到,线程(thread)是执行引擎(Execution Engine)的运行实例,那么线程(thread)就是一个“时间维度”的视角。JVM Stack是运行时数据区(Runtime Data Areas)的一部分,是“空间维度”的视角。两者之间是什么样的关系呢?

Each Java Virtual Machine thread has a private Java Virtual Machine stack, created at the same time as the thread.

那么,对于线程(thread)来说,它就同时具有“时间维度”(Execution Engine)和“空间维度”(JVM Stack)。

A Java Virtual Machine stack stores frames.

method对应于Stack Frame

接着,我们如何看待方法(method)呢?或者说方法(method)是什么呢?方法(method),是一组instruction内容的有序集合;而instruction的执行,就对应着时间的流逝,所以方法(method)也可以理解成一个“时间片段”。

那么,线程(thread)和方法(method)是什么关系呢?线程(thread),从本质上来说,就是不同方法(method)之间的调用。所以,线程(thread)是更大的“时间片段”,而方法(method)是较小的“时间片段”。

上面描述,体现方法(method)是在“时间维度”的考量,在“空间维度”上有哪些体现呢?在“空间维度”上,就体现为Stack Frame。

  • A new frame is created each time a method is invoked.
  • A frame is destroyed when its method invocation completes, whether that completion is normal or abrupt (it throws an uncaught exception).

接下来,介绍current frame、current method和current class三个概念。

Only one frame, the frame for the executing method, is active at any point in a given thread of control. This frame is referred to as the current frame, and its method is known as the current method. The class in which the current method is defined is the current class.

一个方法会调用另外一个方法,另一个方法也有执行结束的时候。那么,current frame是如何变换的呢?

  • A frame ceases to be current if its method invokes another method or if its method completes.
  • When a method is invoked, a new frame is created and becomes current when control transfers to the new method.
  • On method return, the current frame passes back the result of its method invocation, if any, to the previous frame.
  • The current frame is then discarded as the previous frame becomes the current one.

Runtime Data Areas: Stack Frame

对于Stack Frame内存空间,主要分成三个子区域:

  • 第一个子区域,operand stack,是一个栈结构,遵循后进先出(LIFO)的原则;它的大小是由Code属性中的max_stack来决定的。
  • 第二个子区域,local variables,是一个数组结构,通过索引值来获取和设置里面的数据,其索引值是从0开始;它的大小是由Code属性中的max_locals来决定的。
  • 第三个子区域,Frame Data,它用来存储与当前方法相关的数据。例如,一个指向runtime constant pool的引用、出现异常时的处理逻辑(exception table)。

在Frame Data当中,列出其中两个重要数据信息:

  • 第一个数据,instructions,它表示指令集合,是由Code属性中的code[]解析之后的结果。(准确的来说,这里是不对的,instructions可能是位于Method Area当中。我们为了看起来方便,把它放到了这里。)
  • 第二个数据,ref,它是一个指向runtime constant pool的引用。这个runtime constant pool是由具体.class文件中的constant pool解析之后的结果。
frame data
Code_attribute {
    u2 attribute_name_index;
    u4 attribute_length;
    u2 max_stack;
    u2 max_locals;
    u4 code_length;
    u1 code[code_length];
    u2 exception_table_length;
    {   u2 start_pc;
        u2 end_pc;
        u2 handler_pc;
        u2 catch_type;
    } exception_table[exception_table_length];
    u2 attributes_count;
    attribute_info attributes[attributes_count];
}

Stack Frame内的数据类型

在这里,我们要区分开两个概念:存储时的类型 和 运行时的类型。

将一个具体.class文件加载进JVM当中,存放数据的地方有两个主要区域:堆(Heap Area)和栈(Stack Area)。

  • 在堆(Heap Area)上,存放的就是Actual type,就是“存储时的类型”。例如,byte类型就是占用1个byte,int类型就是占用4个byte。
  • 在栈(Stack Area)上,更确切的说,就是Stack Frame当中的operand stack和local variables区域,存放的就是Computational type。这个时候,类型就发生了变化,boolean、byte、char、short都会被转换成int类型来进行计算。

在方法执行的时候,或者说方法里的instruction在执行的时候,需要将相关的数据加载到Stack Frame里;更进一步的说,就是将数据加载到operand stack和local variables两个子区域当中。


当数据加载到operand stack和local variables当中时,需要注意三点:

  • 第一点,boolean, byte, short, char, or int,这几种类型,在local variable和operand stack当中,都是作为int类型进行处理。
  • 第二点,int、float和reference类型,在local variable和operand stack当中占用1个位置
  • 第三点,long和double类型,在local variable和operand stack当中占用2个位置

举个例子,在一个类当中,有一个byte类型的字段。将该类加载进JVM当中,然后创建该类的对象实例,那么该对象实例是存储在堆(Heap Area)上的,其中的字段就是byte类型。当程序运行过程中,会使用到该对象的字段,这个时候就要将byte类型的值转换成int类型进行计算;计算完成之后,需要将值存储到该对象的字段当中,这个时候就会将int类型再转换成byte类型进行存储。

另外,对于Category为1的类型,在operand stack和local variables当中占用1个slot的位置;对于对于Category为2的类型,在operand stack和local variables当中占用2个slot的位置。

Actual type Computational type Category
boolean int 1
byte int 1
char int 1
short int 1
int int 1
float float 1
reference reference 1
long long 2
double double 2

小结

  • Execution Engine是JVM的核心;JVM文档中的Instruction Set就是对Execution Engine的行为描述;线程就是Execution Engine的运行实例。
  • 线程所对应的内存空间是JVM Stack,方法所对应的内存空间是Stack Frame。
  • 在Stack Frame当中,分成local variable、operand stack和frame data三个子区域;在local variable和operand stack中,要注意数据的计算类型和占用的空间大小。
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,142评论 6 498
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,298评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 162,068评论 0 351
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,081评论 1 291
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,099评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,071评论 1 295
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,990评论 3 417
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,832评论 0 273
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,274评论 1 310
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,488评论 2 331
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,649评论 1 347
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,378评论 5 343
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,979评论 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,625评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,796评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,643评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,545评论 2 352

推荐阅读更多精彩内容

  • 任何一台计算机的指令系统一般都包含有几十条到上百条指令,下面按一般计算机的功能把指令划分以下几种类型.(1)算术运...
    onedam阅读 1,412评论 0 0
  • Frame内存结构 JVM Architecture由Class Loader SubSystem、Runtime...
    舍是境界阅读 778评论 0 1
  • 原文链接:https://www.pdai.tech/md/java/jvm/java-jvm-struct.ht...
    漆先生阅读 209评论 0 0
  • HotSpot虚拟机: 基于栈式架构的指令集架构 第一部分 类加载器子系统 类的加载过程 ClassLoading...
    eden_0e6c阅读 712评论 0 0
  • 现在JVM 在很多大厂面试中都有问道,并且在我们实际开发中这个也是对我们实际的开发有重大帮助的,也是你走到高级程序...
    麦穗一足阅读 429评论 0 0