軟件測試之用戶層垃圾回收算法[4] 軟件測試方法
關鍵字:數據庫設計 HASHTABLE *g_pTable;/* 哈希表指針 */
/** 垃圾內存收集算法的初始化函數
@param INT nBucketCount——哈希表的bucket的數量
@return INT——返回CAPI_SUCCESS表示成功;返回CAPI_FAILED表示失敗
*/
INT GC_Init(INT nBucketCount)
{
g_pTable = HashTable_Create(nBucketCount);
if ( g_pTable != NULL )
{
return CAPI_SUCCESS;
}
return CAPI_FAILED;
}
/** 垃圾內存收集算法的內存分配函數
@param size——要分派的內存大小,以字節為單位
@return——成功返回分配到的內存地址;失敗返回NULL
*/
void *GC_Malloc(size_t size)
{
void *p = malloc( size + INT_LEN );
if ( p == NULL )
{
GC_Collect();
p = malloc( size + INT_LEN );
if ( p == NULL )
{
return NULL;
}
}
HashTable_Insert( g_pTable, p, HashInt);
*((INT *)p) = 0;
return (void *)((char *)p+INT_LEN);
}
/** 垃圾收集函數,遍歷哈希表,將所有引用計數為0的內存釋放
@return void——無
*/
void GC_Collect()
{
void *p;
HashTable_EnumBegin(g_pTable);
while ( (p = HashTable_EnumNext(g_pTable)) != NULL )
{
INT *pRef = (INT *)p-1;
if ( *pRef == 0 )
{
HashTable_Delete(g_pTable, p, HashInt, IntCompare, NULL);
GC_Free(p);
}
}
}
注意:上面GC_Malloc()函數里當分配失敗后會調用GC_Collect()函數收集垃圾,然后再繼續分配內存。
7. 手工釋放及循環引用的釋放
由于引用計數不能處理循環引用的情況,另外可能有些特殊情況下想自己手工將某塊內存釋放掉,比如申請了一大塊內存,用完后不馬上釋放會浪費很多內存,調用GC_Collect()函數執行的時間開銷又比較大,所以有必要設計一個可以讓用戶手工釋放的函數,用戶可以通過手工釋放函數去釋放內存,也可以通過手工釋放函數去手工釋放循環引用的內存。
要實現手工釋放功能,必須保證在手工釋放后GC_Collect()函數不會再對這塊內存進行重復釋放。從GC_Collect()函數的實現可以看出它是通過對哈希表的遍歷來查找引用計數為0的內存進行釋放的,因此只要手工釋放時將對應的內存從哈希表中刪除,GC_Collect()函數就不會重復釋放這塊內存了。
下面給出手工釋放函數的編碼實現。
/** 垃圾內存收集算法的手工釋放內存函數
@param void *p——要釋放的內存地址
@return void——無
*/
void GC_ManualFree(void *p)
{
void *pFree = (void *)((char *)p-INT_LEN);
HashTable_Delete(g_pTable, pFree, HashInt, IntCompare, NULL);
free(pFree);
}
可以看出,手工釋放實現也非常簡單,和GC_Free()的區別就是多了一行哈希表的刪除操作而已。使用手工釋放函數給用戶的使用提供了極大的方便,因為用戶可以通過這個函數手工釋放循環引用的內存。
文章來源于領測軟件測試網 http://www.kjueaiud.com/