扫一扫
分享文章到微信
扫一扫
关注官方公众号
至顶头条
作者:baocl 来源:赛迪网技术社区 2007年11月14日
关键字: 常量池 kodakimage
在class文件中,“常量池”是最复杂也最值得关注的内容。 Java是一种动态连接的语言,常量池的作用非常重要,常量池中除了包含代码中所定义的各种基本类型(如int、long等等)和对象型(如String及数组)的常量值还,还包含一些以文本形式出现的符号引用,比如: 类和接口的全限定名; 字段的名称和描述符; 方法和名称和描述符。 在C语言中,如果一个程序要调用其它库中的函数,在连接时,该函数在库中的位置(即相对于库文件开头的偏移量)会被写在程序中,在运行时,直接去这个地址调用函数; 而在Java语言中不是这样,一切都是动态的。编译时,如果发现对其它类方法的调用或者对其它类字段的引用的话,记录进class文件中的,只能是一个文本形式的符号引用,在连接过程中,虚拟机根据这个文本信息去查找对应的方法或字段。 所以,与Java语言中的所谓“常量”不同,class文件中的“常量”内容很非富,这些常量集中在class中的一个区域存放,一个紧接着一个,这里就称为“常量池”。 常量池由多条“常量池项”组成,每一个常量池项又由两部分组成,这里分别称为“常量池项头”和“常量池项体”。 常量池项头表明常量池项的类型,常量池项共分为11种类型,分别为: 常量池项类型 以下介绍kvm中的常量池是如何组织起来的。 数据结构: 在KVM的头文件kvm/vmcommon/h/pool.h中,有以下对常量池项类型的定义: #define CONSTANT_Utf8 1 union constantPoolEntryStruct { 显然,这个数组就将是常量池的核心内容,那么这个数组放在哪里呢?就在下面这个结构中: struct constantPoolStruct { 1、这个结构体中只有一个指针,指向一个常量池项体数组,数组中元素的个数是常量池项数+1,数组中的第一项(即序号为0的那一项)不是实际的常量池项体,而是存放了常量池项的数目,即表明了数组中接下来的元素数。要取得数组的长度信息,只有一个办法,就是读数组的第一个元素,为不造成空指针错误,所以constantPoolStruct在定义的时候就要保证数组的第0个元素必须存在,所以上面的entries在定义时就被指定为长度为1的数组。 单纯从数据结构的设计角度来看,我认为constantPoolStruct的设计并不是很清晰,使用数组的第一个无素来表示数组的长度多少一点显得混乱,明明可以在constantPoolStruct的结构里增加一个变量来表明数组长度,这样不是更清晰吗?之所以这样做,我想也是与class文件中常量池的设计惯例有关。在class文件中, constant_pool紧跟在constant_pool_count之后,而constant_pool_count = constant_pool中实际的项数+1,相当于constant_pool_count也把自己当成了常量池中的第一项。 由此可见,KVM的常量池设计与class文件如出一辙。 2、常量池项体以一个union来表示,而union不带有自身类型的信息,如何知道一个常量池项的类型呢? 在一个class文件的常量池被载入后,生成了constantPoolStruct结构体的实例,在其中constantPoolEntryStruct数组的最后一项之后,一定会跟随一个字节数组,这个数组中的每一个字节就是一个“常量池项头”,长度与实际的常量池项数相同,即constant_pool_count-1,在这个字节中就指明了相应常量池项的类型。 程序实现: 构造常量池的代码段主要在kvm/vmcommon/src/loader.c的loadConstantPool()函数中,函数原形如下: static POINTERLIST loadConstantPool(FILEPOINTER_HANDLE ClassFileH, INSTANCE_CLASS CurrentClass); 两个参数分别为类文件的句柄以及当前被载入类的指针。 这个函数的总体流程如下: 1- 循环读取文件中常量池中所有项,把,把各项内容存入临时数组RowPool中;(L649~L740) 2- 计算常量池所占空间大小(以constantPoolEntryStruct枚举体数计),并申请常量池空间;(L742~L757) 3- 循环读取暂存在RowPool中的常量信息,为常量池赋值。 其中第2步值得一看,记算空间大小的那一行如下: int tableSize = numberOfEntries + ((numberOfEntries + (4 - 1)) >> 2); loadConstantPool函数执行过程中,会把新生成的常量池指针赋给CurrentClass->constPool,这样,这个类实例中就有完整的常量池了。 |
如果您非常迫切的想了解IT领域最新产品与技术信息,那么订阅至顶网技术邮件将是您的最佳途径之一。
现场直击|2021世界人工智能大会
直击5G创新地带,就在2021MWC上海
5G已至 转型当时——服务提供商如何把握转型的绝佳时机
寻找自己的Flag
华为开发者大会2020(Cloud)- 科技行者