国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 學(xué)院 > 開發(fā)設(shè)計(jì) > 正文

KVM的常量池

2019-11-18 16:25:50
字體:
供稿:網(wǎng)友

在class文件中,“常量池”是最復(fù)雜也最值得關(guān)注的內(nèi)容。

java是一種動(dòng)態(tài)連接的語言,常量池的作用非常重要,常量池中除了包含代碼中所定義的各種基本類型(如int、long等等)和對(duì)象型(如String及數(shù)組)的常量值還,還包含一些以文本形式出現(xiàn)的符號(hào)引用,比如:

類和接口的全限定名;

字段的名稱和描述符;

方法和名稱和描述符。

在C語言中,如果一個(gè)程序要調(diào)用其它庫中的函數(shù),在連接時(shí),該函數(shù)在庫中的位置(即相對(duì)于庫文件開頭的偏移量)會(huì)被寫在程序中,在運(yùn)行時(shí),直接去這個(gè)地址調(diào)用函數(shù);

而在Java語言中不是這樣,一切都是動(dòng)態(tài)的。編譯時(shí),如果發(fā)現(xiàn)對(duì)其它類方法的調(diào)用或者對(duì)其它類字段的引用的話,記錄進(jìn)class文件中的,只能是一個(gè)文本形式的符號(hào)引用,在連接過程中,虛擬機(jī)根據(jù)這個(gè)文本信息去查找對(duì)應(yīng)的方法或字段。

所以,與Java語言中的所謂“常量”不同,class文件中的“常量”內(nèi)容很非富,這些常量集中在class中的一個(gè)區(qū)域存放,一個(gè)緊接著一個(gè),這里就稱為“常量池”。

常量池由多條“常量池項(xiàng)”組成,每一個(gè)常量池項(xiàng)又由兩部分組成,這里分別稱為“常量池項(xiàng)頭”和“常量池項(xiàng)體”。

常量池項(xiàng)頭表明常量池項(xiàng)的類型,常量池項(xiàng)共分為11種類型,分別為:

常量池項(xiàng)類型

說明

CONSTANT_Utf8

1

UTF-8編碼的Unicode字符串

CONSTANT_Integer

3

int型常量

CONSTANT_Float

4

Float型常量

CONSTANT_Long

5

Long型常量

CONSTANT_Double

6

double型常量

CONSTANT_Class

7

對(duì)一個(gè)class的符號(hào)引用

CONSTANT_String

8

String型常量

CONSTANT_Fieldref

9

對(duì)一個(gè)字段的符號(hào)引用

CONSTANT_Methodref

10

對(duì)一個(gè)類方法的符號(hào)引用

CONSTANT_InterfaceMedthodref

11

對(duì)一個(gè)接口方法的符號(hào)引用

CONSTANT_NameAndType

12

對(duì)名稱和類型的符號(hào)引用

常量池項(xiàng)體中存放的就是對(duì)應(yīng)的常量數(shù)據(jù),比如各種數(shù)值型的常量或者字符串等等。

以下介紹kvm中的常量池是如何組織起來的。

 

數(shù)據(jù)結(jié)構(gòu):

在KVM的頭文件kvm/vmcommon/h/pool.h中,有以下對(duì)常量池項(xiàng)類型的定義:

Word-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: windowtext 0.5pt solid">
#define CONSTANT_Utf8                       1
#define CONSTANT_Integer                    3
#define CONSTANT_Float                      4
#define CONSTANT_Long                       5
#define CONSTANT_Double                     6
#define CONSTANT_Class                      7
#define CONSTANT_String                     8
#define CONSTANT_Fieldref                   9
#define CONSTANT_Methodref                  10
#define CONSTANT_InterfaceMethodref    11
#define CONSTANT_NameAndType            12
 以及常量池項(xiàng)體結(jié)構(gòu)的定義:
union constantPoolEntryStrUCt {
    struct { 
        unsigned short classIndex;
        unsigned short nameTypeIndex;
    }               method;  /* Also used by Fields */
    CLASS           clazz;
    INTERNED_STRING_INSTANCE String;
    cell           *cache;   /* Either clazz or String */
    cell            integer;
    long            length;
    NameTypeKey     nameTypeKey;
    NameKey         nameKey;
    UString         ustring;
};

class文件中,常量池項(xiàng)有很多種類,每一個(gè)常量池項(xiàng)的大小都不同,而對(duì)于常量池的使用又是如此之多,最好能夠使用數(shù)組來索引,這樣可以提高效率,所以KVM里使用union來代表一個(gè)常池項(xiàng),union的每一項(xiàng)是常量池項(xiàng)的一種可能的數(shù)據(jù)類型,這樣每一項(xiàng)都有了相同的大小,可以構(gòu)造數(shù)組。

顯然,這個(gè)數(shù)組就將是常量池的核心內(nèi)容,那么這個(gè)數(shù)組放在哪里呢?就在下面這個(gè)結(jié)構(gòu)中:

struct constantPoolStruct { 
    union constantPoolEntryStruct entries[1];
};


這就是常量池。這個(gè)常量池的設(shè)計(jì)很有意思:

1、這個(gè)結(jié)構(gòu)體中只有一個(gè)指針,指向一個(gè)常量池項(xiàng)體數(shù)組,數(shù)組中元素的個(gè)數(shù)是常量池項(xiàng)數(shù)+1,數(shù)組中的第一項(xiàng)(即序號(hào)為0的那一項(xiàng))不是實(shí)際的常量池項(xiàng)體,而是存放了常量池項(xiàng)的數(shù)目,即表明了數(shù)組中接下來的元素?cái)?shù)。要取得數(shù)組的長(zhǎng)度信息,只有一個(gè)辦法,就是讀數(shù)組的第一個(gè)元素,為不造成空指針錯(cuò)誤,所以constantPoolStruct在定義的時(shí)候就要保證數(shù)組的第0個(gè)元素必須存在,所以上面的entries在定義時(shí)就被指定為長(zhǎng)度為1的數(shù)組。

單純從數(shù)據(jù)結(jié)構(gòu)的設(shè)計(jì)角度來看,我認(rèn)為constantPoolStruct的設(shè)計(jì)并不是很清晰,使用數(shù)組的第一個(gè)無素來表示數(shù)組的長(zhǎng)度多少一點(diǎn)顯得混亂,明明可以在constantPoolStruct的結(jié)構(gòu)里增加一個(gè)變量來表明數(shù)組長(zhǎng)度,這樣不是更清晰嗎?之所以這樣做,我想也是與class文件中常量池的設(shè)計(jì)慣例有關(guān)。在class文件中, constant_pool緊跟在constant_pool_count之后,而constant_pool_count = constant_pool中實(shí)際的項(xiàng)數(shù)+1,相當(dāng)于constant_pool_count也把自己當(dāng)成了常量池中的第一項(xiàng)。

由此可見,KVM的常量池設(shè)計(jì)與class文件如出一轍。

2、常量池項(xiàng)體以一個(gè)union來表示,而union不帶有自身類型的信息,如何知道一個(gè)常量池項(xiàng)的類型呢?

在一個(gè)class文件的常量池被載入后,生成了constantPoolStruct結(jié)構(gòu)體的實(shí)例,在其中constantPoolEntryStruct數(shù)組的最后一項(xiàng)之后,一定會(huì)跟隨一個(gè)字節(jié)數(shù)組,這個(gè)數(shù)組中的每一個(gè)字節(jié)就是一個(gè)“常量池項(xiàng)頭”,長(zhǎng)度與實(shí)際的常量池項(xiàng)數(shù)相同,即constant_pool_count-1,在這個(gè)字節(jié)中就指明了相應(yīng)常量池項(xiàng)的類型。

 

程序?qū)崿F(xiàn):

構(gòu)造常量池的代碼段主要在kvm/vmcommon/src/loader.c的loadConstantPool()函數(shù)中,函數(shù)原形如下:

static POINTERLIST

loadConstantPool(FILEPOINTER_HANDLE ClassFileH, INSTANCE_CLASS CurrentClass);

兩個(gè)參數(shù)分別為類文件的句柄以及當(dāng)前被載入類的指針。

這個(gè)函數(shù)的總體流程如下:

1- 循環(huán)讀取文件中常量池中所有項(xiàng),把,把各項(xiàng)內(nèi)容存入臨時(shí)數(shù)組RowPool中;(L649~L740)

2- 計(jì)算常量池所占空間大小(以constantPoolEntryStruct枚舉體數(shù)計(jì)),并申請(qǐng)常量池空間;(L742~L757)

3- 循環(huán)讀取暫存在RowPool中的常量信息,為常量池賦值。

其中第2步值得一看,記算空間大小的那一行如下:


 

int tableSize = numberOfEntries + ((numberOfEntries + (4 - 1)) >> 2);

一個(gè)constantPoolEntryStruct枚舉體的大小為4,前面講過,在constantPoolEntryStruct數(shù)組的后要跟有一個(gè)字節(jié)數(shù)組來存放常量池項(xiàng)的類型信息,即每一個(gè)constantPoolEntryStruct要對(duì)應(yīng)1個(gè)字節(jié)的常量池項(xiàng)頭,所以當(dāng)以constantPoolEntryStruct枚舉體數(shù)為單位給常量池項(xiàng)頭數(shù)組申請(qǐng)空間時(shí),需要向4字節(jié)對(duì)齊,每多1~4個(gè)常量池項(xiàng)頭,就要多申請(qǐng)一個(gè)constantPoolEntryStruct。這一句就是這個(gè)意思。

loadConstantPool函數(shù)執(zhí)行過程中,會(huì)把新生成的常量池指針賦給CurrentClass->constPool,這樣,這個(gè)類實(shí)例中就有完整的常量池了。

進(jìn)入討論組討論。

(出處:http://m.survivalescaperooms.com)



發(fā)表評(píng)論 共有條評(píng)論
用戶名: 密碼:
驗(yàn)證碼: 匿名發(fā)表
主站蜘蛛池模板: 文安县| 东港市| 和静县| 抚顺县| 册亨县| 成都市| 从江县| 鹤峰县| 綦江县| 林州市| 东至县| SHOW| 南投县| 永宁县| 黄梅县| 德昌县| 满城县| 红河县| 五指山市| 德州市| 沙河市| 新野县| 哈密市| 修武县| 澄迈县| 福州市| 灌南县| 当阳市| 新和县| 阿尔山市| 南川市| 高唐县| 奉新县| 兖州市| 潢川县| 铜陵市| 拉萨市| 葫芦岛市| 滦南县| 上蔡县| 蒲城县|