日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

java解析dxf文件_浅析JVM方法解析、创建和链接

發布時間:2023/12/10 编程问答 32 豆豆
生活随笔 收集整理的這篇文章主要介紹了 java解析dxf文件_浅析JVM方法解析、创建和链接 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

一:前言

上周末寫了一篇文章《你知道Java類是如何被加載的嗎?》,分析了HotSpot是如何加載Java類的,干脆趁熱打鐵,本周末再來分析下Hotspot又是如何解析、創建和鏈接類方法的。

二:Class文件中的Java方法

Java類在編譯后會被編譯成 Class 文件,在幾年前寫的《Jvm之用java解析class文件》中,我對 Class 文件的結構進行了分析,里面已經講過了Java 方法在 Class 文件中的結構,今天就再溫故而知新下。

先來看下 Class 文件的結構:

ClassFile
  • methods_count 記錄了 Class 文件中一共有多少方法。
  • methods 是個數組,包含 Class 文件的所有方法。

methods 的數組類型為 method_info,每個 method_info 對應一個 Java 方法。

method_info {u2 access_flags;u2 name_index;u2 descriptor_index;u2 attributes_count;attribute_info attributes[attributes_count]; }
  • access_flags 是方法的訪問權限。
  • name_index 是方法名在常量池中的索引。
  • descriptor_index 是方法描述符在常量池中的索引。
  • attributes_count 記錄了方法一共有多少屬性。
  • attributes是個數組,包含了方法的所有屬性。

attributes 中的每一項都是方法的一個屬性,其中代表字節碼的屬性為 Code_attribute:

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]; }
  • max_stack 表示當前方法操作數棧的最大深度。
  • max_locals 表示當前方法局部變量的最大個數。
  • code[code_length] 記錄了方法中的字節碼指令

總的來說,Class 文件中對方法的描述還是很簡潔清晰的。

三:HotSpot 如何解析 Java 方法

Class 文件相當于 Java 類的模板,JVM 在讀取 Class 文件后,會根據這個模板,建立 Java 類在虛擬機中的模型。

在上篇文章《你知道Java類是如何被加載的嗎?》中,我提到了 ClassFileParser,它是HotSpot 加載類所需要的一員大將,通過名字我們就能猜出它的作用:類文件解析器。

還記得Class在JVM中對應的 InstanceKlass 是如何創建的嗎?不記得話看一下下面這段代碼來回憶下。

ClassFileParser

上面這段代碼主要是創建了一個ClassFileParser,并調用了其create_instance_klass()來創建 InstanceKlass。但是對于Class文件的解析,是在 create_instance_klass()之前就完成了的。當經過一系列初始化操作后,ClassFileParser 便在其構造函數的末尾,調用 parse_stream(stream, CHECK),開始了 Class 文件的解析之旅。

在 parse_stream()中,ClassFileParser 會對整個Class文件解析解析,包括常量池、字段、父類、接口等信息,當然也包括類方法。用來解析所有類方法的函數為:parse_methods()。

void

ClassFileParser 對于 Class文件的解析是流式的,parse_methods()先通過 cfs->get_u2_fast() 拿到方法數量,接著便開始進行遍歷,調用 parse_method()依次解析每個類方法。

從Class文件中method_info的定義可知,method 基本上所有信息都存儲在method_info中的attributes[] 數組中,所以對于method的解析,基本上也就是在遍歷attributes[] 數組。

method_info 中的attributes[] 數組是用來存放方法的各個屬性的,其中包括Code屬性、Exception屬性、MethodParameters屬性、Synthetic屬性。parse_method()要做的主要工作,就是遍歷attributes[] 數組,解析每個屬性。

下面我們來便來各個擊破,看看上面這些屬性是如何被解析的。

3.1 解析 Code 屬性

(1)獲取maxStacks、maxLocals 和 code length

if

(2)獲取字節碼指令首地址

code_start

(3)解析方法中的異常處理表

exception_table_length

(4)解析Code屬性中的屬性表,如 LineNumberTables、LocalVariableTables、LocalVariableTypeTables。主要是用于記錄一些調試信息。

3.2 解析 Exception 屬性

Exception 屬性記錄了方法可能拋出的異常。

checked_exceptions_start

3.3 解析 MethodParameters 屬性

MethodParameters 屬性記錄了方法的參數信息。

method_parameters_seen

3.4 解析 Synthetic 屬性

Synthetic 屬性表示成員是在編譯期自動為Class生成,如內部類提供給外部類用來訪問內部成員的 access()方法。

access_flags

如果在解析到該屬性,直接調用 set_is_synthetic()標志下即可。

由上面的解析過程可知,ClassFileParser 主要就是按照Java虛擬機規范對Class文件結構的定義進行流式解析。

四:HotSpot 如何創建 Java 方法

經過第三節的解析,ClassFileParser 已經從Class文件中獲取到了方法的所有信息。接下來要做的,便是通過讀取的信息,創建 Java 方法在 JVM 中的數據模型。

在HotSpot中,Java方法對應的數據結構為 Method,定義在 method.hpp 中

class

創建 Method 主要分為下面幾步。

4.1 分配方法對應的 Method

Method

4.2 將解析方法時讀取到信息填充到 Method 中

m->set_constants(_cp); m->set_name_index(name_index); m->set_signature_index(signature_index); ...... // Fill in code attribute information m->set_max_stack(max_stack); m->set_max_locals(max_locals); ...... // Copy byte codes m->set_code((u1*)code_start); ...... // Copy exception table if (exception_table_length > 0) {Copy::conjoint_swap_if_needed<Endian::JAVA>(exception_table_start,m->exception_table_start(),exception_table_length * sizeof(ExceptionTableElement),sizeof(u2)); } ......

Method 中將一些只讀數據都存放到了它的 _constMethod 中,_constMethod 類型為ConstMethod,定義在 constMethod.hpp 中。

舉個例子,方法的字節碼指令就存放在 ConstMethod 中,不過這么說不太嚴謹,字節碼指令并不是直接存放在 ConstMethod 內部,而是緊跟著 ConstMethod 存放在內存中。

我們再看看上面的填充邏輯,調用了 m->set_code((u1*)code_start) 來存放字節碼指令首地址,Method 其實是直接調用了 ConstMethod 的 set_code():

void

ConstMethod的set_code()也很簡單:

void

首先調用code_base()獲取存放字節碼的地址,接著便調用memcpy(),將字節碼指令從 code 處拷貝到code_base()處。

code_base()代碼如下:

address

因為 this 本身是指針,所以 this + 1 獲取的地址為:

constMethod 首地址 + sizeOf(ConstMethod)

所以字節碼指令存放在ConstMethod之后:

存放好字節碼指令后,以后當調用該方法時,就可以從 ConstMethod 中獲取到字節碼指令首地址,從而進行取指執行了。

五:HotSpot 如何鏈接 Java 方法

上面只是在加載Class文件時對Java方法進行了解析和創建,而Java 方法的鏈接是發生在所屬InstanceKlass 的初始化時期。

一般來說,Class文件在被加載成 InstanceKlass 后不會立即初始化,而是等到實例化 Obejct、反射獲取字段、方法信息,或者調用static方法等時機才會初始化。

InstanceKlass在初始化時會調用 link_class()對類進行鏈接,在類的鏈接過程中,便會調用 InstanceKlass的 link_methods()方法,對類的所有方法進行鏈接。

對單個 Method 進行鏈接的方法為:Method::link_method(const methodHandle& h_method, TRAPS),方法鏈接主要就是做的事就是設置 Method 的 interpreter_entry:

address

上面首先通過 entry_for_method(h_method)獲取方法的入口例程,關于這個例程是干什么的,可以看看之前寫的《JVM方法執行的來龍去脈》,簡單來說,HotSpot對于Java方法的執行不是簡單的從方法字節碼首地址處進行取指執行即可,在進行字節碼指令執行之前,需要為Java方法創建棧幀、局部變量表等事情,而這些事情是通用的,所以HotSpot將這些事情統一到一起,對Java方法的執行做了一層封裝,而例程便是這個封裝的入口。

HotSpot 提前為各種類型的方法創建好了一系列例程,所以 entry_for_method(h_method)便是根據方法類型,從例程表中查詢到對應類型的例程。

查詢到例程后,便調用set_interpreter_entry(entry),將例程的入口地址保存到Method中:

void

保存例程的入口地址后,以后調用Java方法時,便可以從Method中獲取例程的入口地址,跳到此處執行。

六:總結

通過上面的分析,我們了解了Java方法在Class文件中的結構,以及方法的解析、創建及鏈接。

解析過程主要是流式讀取Class文件,獲取方法在Class文件中的信息。

創建過程主要是創建Java方法對應的Method,并將解析過程讀取的信息填充到Method中。

鏈接過程主要是根據方法類型,獲取并保存方法對應的入口例程的地址。

我的文章只是個引子,畢竟短短篇幅無法囊括JVM浩瀚如煙的源碼。如果想對 HotSpot 如何處理 Java 方法的細節深入了解的話,想必最好的方式還是自己去閱讀和調試 OpenJDK,

罷了,寫完,關燈,睡覺!

聽說喜歡點關注的同學都長得帥

總結

以上是生活随笔為你收集整理的java解析dxf文件_浅析JVM方法解析、创建和链接的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。