Dalvik 虛擬機器 之 雜湊表使用篇
前面介紹了dvm裡德雜湊表提供的方法。下面就以InternedString實現為例介紹一下雜湊表的使用。我們將看到dvm裡雜湊表的設計非常直觀,其使用更是簡單明了。
Interned String是指java虛擬機器將某些字串“內部化”,和不同字串的最大區別就是在虛擬機器內部永遠只會存在改字串的唯一執行個體。多次分配改string都將返回該字串唯一的執行個體。也就是說 對於Interned string a 和b,我們可以使用比較子(==)來判斷他們是否相同。而普通的字串必須使用equal函數。
Java Interned String分為兩類,一類是literal string。就是字元常量。比如通過以下語句得到的字串:
String literal = "I am a literal string";
另一類是使用者調用 java.lang.String.intern() 得到的。 與字元常量不同,該類字串只能是弱引用的(weakly referenced)。
DVM interned string 實現 在 dalvik/vm/Intern.h dalvik/vm/Intern.cpp 裡。 下面將看看它是如何使用hash來實現的。
/*
* Prep string interning.
*/
bool dvmStringInternStartup()
{
dvmInitMutex(&gDvm.internLock);
gDvm.internedStrings = dvmHashTableCreate(256, NULL);
if (gDvm.internedStrings == NULL)
return false;
gDvm.literalStrings = dvmHashTableCreate(256, NULL);
if (gDvm.literalStrings == NULL)
return false;
return true;
}
首先是在啟動函數裡,調用dvmHashTableCreate來建立兩個雜湊表,一個存放 interned string,一個存放literal string。初始的表大小為256。單元釋放函數為NULLL。
/*
* Chuck the intern list.
*
* The contents of the list are StringObjects that live on the GC heap.
*/
void dvmStringInternShutdown()
{
if (gDvm.internedStrings != NULL || gDvm.literalStrings != NULL) {
dvmDestroyMutex(&gDvm.internLock);
}
dvmHashTableFree(gDvm.internedStrings);
gDvm.internedStrings = NULL;
dvmHashTableFree(gDvm.literalStrings);
gDvm.literalStrings = NULL;
}
這是相反的過程,調用dvmHashTableFree清理掉所有雜湊表單元,然後釋放掉雜湊表本省。
static StringObject* lookupString(HashTable* table, u4 key, StringObject* value)
{
void* entry = dvmHashTableLookup(table, key, (void*)value,
dvmHashcmpStrings, false);
return (StringObject*)entry;
}
搜尋字串更簡單,只需要調用雜湊表搜尋函數dvmHashTableLookup。傳入的雜湊表可能是前面提到的 gDvm.internedStrings或者gDvm.literalStrings。最後一個參數isAdd為false,標識這是純粹的尋找,而不需要在尋找未果的情況下插入。
static StringObject* insertString(HashTable* table, u4 key, StringObject* value)
{
if (dvmIsNonMovingObject(value) == false) {
value = (StringObject*)dvmCloneObject(value, ALLOC_NON_MOVING);
}
void* entry = dvmHashTableLookup(table, key, (void*)value,
dvmHashcmpStrings, true);
return (StringObject*)entry;
}
插入字串也是簡單的調用函數dvmHashTableLookup並且傳入isAdd為true(最後一個參數)。
/*
* Clear white references from the intern table.
*/
void dvmGcDetachDeadInternedStrings(int (*isUnmarkedObject)(void *))
{
/* It's possible for a GC to happen before dvmStringInternStartup()
* is called.
*/
if (gDvm.internedStrings != NULL) {
dvmLockMutex(&gDvm.internLock);
dvmHashForeachRemove(gDvm.internedStrings, isUnmarkedObject);
dvmUnlockMutex(&gDvm.internLock);
}
}
調用dvmHashForeachRemove,將所有單元執行isUnmarkedObject判斷,所有返回1的都被表示為不可用,從而達到了清除的目的。
我們看到,有了雜湊表的支援操作後,interned string的實現非常的直觀而又簡潔。