位元組碼檔案解剖

海山了-發表於2024-07-05

#### 前提提要:

.java檔案透過java -c 生成.class檔案,這部分並非是JVM需要處理的部分,JVM處理的部分是基於生成的class檔案,生成的部分是由編譯器來負責

一個位元組碼檔案的主要組成部分

image-20240705134632708

使用工具說明

idea的JclassLib外掛

使用步驟:

  1. 執行程式碼(只要你更新了程式碼就需要,或者build)
  2. image-20240705135213385

基礎資訊介紹

image-20240705134952556

魔數

魔數並非在這裡展示,魔數其實有點類似一個檔案的格式中的一部分,所有的軟體開發中關於開啟檔案都會這麼設計,用於識別說我們能否成功開啟

java中是開頭是cafebabe

其他檔案如下:

image-20240705135756018

主版本號

1.2後大版本對應的公式是主版本號-44

image-20240705135921638

關於版本號可能遇到的problem及解法
  1. 版本不匹配
    1. 提高java版本
    2. 降低依賴版本

image-20240705140132316

在這之中可能還會遇到的問題:jdk版本存在bug,雖然很多人都說什麼永遠jdk8,但是實際使用上jdk8在效能上以及開發上可能會比jdk17多不少工作量,例如我之前嘗試轉為http2,而在jdk8需要引入其他依賴,而jdk9則可以直接轉

常量池介紹以及屬性介紹

此常量池非JVM中的字串常量池,僅僅是當前class檔案中為了降低一定的空間佔用和加快JVM解析class檔案而使用的常量池而已

下列討論也僅侷限於位元組碼檔案中的常量池,不會涉及JVM部分

在此先給常量池定論:為了節省空間而使用的池化技術

首先從欄位入手:

image-20240705141818983

image-20240705142237700

Problem1:為什麼aaa變數可以開啟?而其他的不行?

解答:是因為他使用的是static和final同時修飾

所有以cp開頭的都最終指向了常量池中的一個記錄,例如aaa這個變數名,以及對應的aaa的型別string,具體內容如下:

image-20240705142003501

image-20240705142022100

我們再看看ConstantValue的資訊:

image-20240705142358192

problem2:這個屬性名索引為何存在且為什麼要是constantValue?

首先回答一下為什麼要有constantvalue,這是由於我們使用final修飾了,所以最終的效果就是有了一個指向constantValue的引用,也就是我們java,位元組碼層面實現我們final修飾不可改變的效果,如下圖所示,而這個屬性值為什麼存在也不言而喻了

image-20240705144543867

最後回到正題:我們可以發現當String aaa和Stirng ccc都="aaa"時,他的常量值索引都指向7

image-20240705144724267

那麼7的內容是什麼?7的型別是string_info,而之中又指向了8?

image-20240705144925308

8才是真正的aaa

image-20240705145000278

那麼問題來了?

為什麼要這麼設計?

關於欄位中的constant_value為什麼要指向string?然後string再指向其中的一個具體的utf8_info呢?

因為最終jvm會有一個string常量池,我們要儲存string和utf8_info中儲存的值的關係,好方便之後我們將其儲存到常量池中

追問:那為什麼不直接儲存在對應的string中,也即我們string不存符號引用而是直接存對應的常量?

這樣的話如果有其他變數也紙箱這裡應該也沒問題吧?

沒錯,但是例如string abc="abc",對應的變數名也要儲存,而java中採用的變數名的引用就指向對應的utf_8的"abc"

那麼abc直接指向這個string不行嗎?

可以,不過這樣的話,能夠更節省一些空間複雜度,但是會消耗更多的時間,尤其對於變數之後執行中的處理

總結

常量池是把對應的我們會使用到的常量抽出來,無論是各個引數或者變數名類名等等,他的核心之一就是要複用

而欄位在目前階段只會對於final static修飾的,因為目前能夠處理的也只有些final和static修飾的值,其他是不行的,也就是編譯階段能處理的也就這一些了

其他欄位的賦值需要之後類的生命週期在各個階段再進行賦值

方法介紹

image-20240705152339655

其中位元組碼部分就是對應方法的執行流程

而異常表主要是trycatch才會有的

而雜項對應的運算元棧的深度是位元組碼執行之中對於運算元棧使用的時候會使用到的棧的深度(與資料結構無異,而最大深度是因為在這之中便可以計算出來)

image-20240705152458362

區域性變數最大槽數是這裡:也就是方法中使用的區域性變數,包括引數等等

image-20240705152926361

關於屬性就不贅述了,意義不大

相關文章