Dalvik VM Hash - implementation

Dalvik虚拟机 之 哈希表实现篇

前面两篇分别介绍了dvm里哈希表的接口和使用。下面我们来看看dvm里哈希表是怎么实现的。

 

数据结构

/*

* One entry in the hash table. "data" values are expected to be (or have

* the same characteristics as) valid pointers. In particular, a NULL

* value for "data" indicates an empty slot, and HASH_TOMBSTONE indicates

* a no-longer-used slot that must be stepped over during probing.

*

* Attempting to add a NULL or tombstone value is an error.

*

* When an entry is released, we will call (HashFreeFunc)(entry->data).

*/

struct HashEntry {

u4 hashValue;

void* data;

};

该结构表示一个哈希单元。它由两部分,一个四字节空间的哈希值和一个不定长的真正的数据部分。在该单元被清理时,该数据部分所占据的内存会被函数调用(HashFreeFunc)(entry->data)清理掉。该清理函数是在哈希表创建时传入的(dvmHashTableCreate()的第二个参数)。

/*

* Expandable hash table.

*

* This structure should be considered opaque.

*/

struct HashTable {

int tableSize; /* must be power of 2 */

int numEntries; /* current #of "live" entries */

int numDeadEntries; /* current #of tombstone entries */

HashEntry* pEntries; /* array on heap */

HashFreeFunc freeFunc;

pthread_mutex_t lock;

};

该结构表示一个哈希表。其成员变量分别是

tableSize: 哈希表的大小,必须是2的幂次。

numEntries: 当前哈希表用于的有效单元数量

numDeadEntries: 改哈希表拥有的无效单元数量。

pEntries: 表示指向该哈希表单元数据的指针

freeFunc: 哈希表单元释放函数

lock:用于同步访问该哈希表的锁。

 

我们后面会看到,哈希表实现中对于无效单元只是简单的将其哈希值表示为一个常量,而没有调用释放函数:

#define HASH_TOMBSTONE ((void*) 0xcbcacccd) // invalid ptr value

哈希表创建

/*

* Create and initialize a hash table.

*/

HashTable* dvmHashTableCreate(size_t initialSize, HashFreeFunc freeFunc)

{

HashTable* pHashTable;

 

assert(initialSize > 0);

 

pHashTable = (HashTable*) malloc(sizeof(*pHashTable));

if (pHashTable == NULL)

return NULL;

 

dvmInitMutex(&pHashTable->lock);

 

pHashTable->tableSize = dexRoundUpPower2(initialSize);

pHashTable->numEntries = pHashTable->numDeadEntries = 0;

pHashTable->freeFunc = freeFunc;

pHashTable->pEntries =

(HashEntry*) malloc(pHashTable->tableSize * sizeof(HashEntry));

if (pHashTable->pEntries == NULL) {

free(pHashTable);

return NULL;

}

 

memset(pHashTable->pEntries, 0, pHashTable->tableSize * sizeof(HashEntry));

return pHashTable;

}

 

首先用断言检查传入的初始大小必须大于0。然后用malloc分配本地内存最为哈希表的空间。由于分配的是本地内存,该哈希表不会被垃圾收集,并且需要在不使用时调用free()来显式的释放空间,否则将引起内存泄露。接下来初始化访问锁。随后调用dexRoundUpPower2来保证初始大小为2幂次方对齐。将有效单元数量和无效单元数量初始化为0。将参数传入的释放函数存放在freeFunc变量里。接着调用malloc为单元指针分配空间。 最后memset整个单元后返回改哈希表结构指针。

 

 

哈希表清理

 

/*

* Clear out all entries.

*/

void dvmHashTableClear(HashTable* pHashTable)

{

HashEntry* pEnt;

int i;

 

pEnt = pHashTable->pEntries;

for (i = 0; i < pHashTable->tableSize; i++, pEnt++) {

if (pEnt->data == HASH_TOMBSTONE) {

// nuke entry

pEnt->data = NULL;

} else if (pEnt->data != NULL) {

// call free func then nuke entry

if (pHashTable->freeFunc != NULL)

(*pHashTable->freeFunc)(pEnt->data);

pEnt->data = NULL;

}

}

 

pHashTable->numEntries = 0;

pHashTable->numDeadEntries = 0;

}

dvmHashTableClear实现。它遍历每个单元,对于无效的单元,简单的将该单元数据区置为NULL。对有效单元调用释放函数后将数据区置为NULL。

 

 

哈希表释放

/*

* Free the table.

*/

void dvmHashTableFree(HashTable* pHashTable)

{

if (pHashTable == NULL)

return;

dvmHashTableClear(pHashTable);

free(pHashTable->pEntries);

free(pHashTable);

}

首先调用dvmHashTableClear清理多有单元数据,然后free掉哈希表结构中为单元指针分配的内存,最后free掉该哈希表本身占据的内存。

 

 

哈希表查找和插入单元

哈希表查找,插入新单元是被放到同一个函数dvmHashTableLookup里实现的。用最后一个参数doAdd来区分开来。

首次是查找的实现,它从第一个单元开始遍历,如果该单元满足下面的条件

“pEntry->data != HASH_TOMBSTONE  && pEntry->hashValue == itemHash && (*cmpFunc)(pEntry->data, item) == 0”

也就是说必须 不能使无效单元,而且哈希值相等,并且调用比较函数的结果相符(返回值为0)。

如果doAdd为1,则进行插入操作。再插入之前,需要判断当前表示空间是否足够容纳新插入一个单元,不够的话需要扩展空间。

 

哈希表删除

和查找类似,也是根据哈希值找到第一个单元后,比较该单元的数值指针的值和带比较的是否一致。一致的话就表示该单元哈希值为常量HASH_TOMBSTONE。

 

 

 

 

 

 

 

 

 

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值