接下来我们继续追踪普通对象的异步删除 lazyfreeFreeObjectFromBioThread 是如何进行的,请仔细阅读代码注释。
- void lazyfreeFreeObjectFromBioThread(robj *o) {
- decrRefCount(o); // 降低对象的引用计数,如果为零,就释放
- atomicDecr(lazyfree_objects,1); // lazyfree_objects 为待释放对象的数量,用于统计
- }
- // 减少引用计数
- void decrRefCount(robj *o) {
- if (o->refcount == 1) {
- // 该释放对象了
- switch(o->type) {
- case OBJ_STRING: freeStringObject(o); break;
- case OBJ_LIST: freeListObject(o); break;
- case OBJ_SET: freeSetObject(o); break;
- case OBJ_ZSET: freeZsetObject(o); break;
- case OBJ_HASH: freeHashObject(o); break; // 释放 hash 对象,继续追踪
- case OBJ_MODULE: freeModuleObject(o); break;
- case OBJ_STREAM: freeStreamObject(o); break;
- default: serverPanic("Unknown object type"); break;
- }
- zfree(o);
- } else {
- if (o->refcount <= 0) serverPanic("decrRefCount against refcount <= 0");
- if (o->refcount != OBJ_SHARED_REFCOUNT) o->refcount--; // 引用计数减 1
- }
- }
- // 释放 hash 对象
- void freeHashObject(robj *o) {
- switch (o->encoding) {
- case OBJ_ENCODING_HT:
- // 释放字典,我们继续追踪
- dictRelease((dict*) o->ptr);
- break;
- case OBJ_ENCODING_ZIPLIST:
- // 如果是压缩列表可以直接释放
- // 因为压缩列表是一整块字节数组
- zfree(o->ptr);
- break;
- default:
- serverPanic("Unknown hash encoding type");
- break;
- }
- }
- // 释放字典,如果字典正在迁移中,ht[0] 和 ht[1] 分别存储旧字典和新字典
- void dictRelease(dict *d)
- {
- _dictClear(d,&d->ht[0],NULL); // 继续追踪
- _dictClear(d,&d->ht[1],NULL);
- zfree(d);
- }
- // 这里要释放 hashtable 了
- // 需要遍历第一维数组,然后继续遍历第二维链表,双重循环
- int _dictClear(dict *d, dictht *ht, void(callback)(void *)) {
- unsigned long i;
- /* Free all the elements */
- for (i = 0; i < ht->size && ht->used > 0; i++) {
- dictEntry *he, *nextHe;
- if (callback && (i & 65535) == 0) callback(d->privdata);
- if ((he = ht->table[i]) == NULL) continue;
- while(he) {
- nextHe = he->next;
- dictFreeKey(d, he); // 先释放 key
- dictFreeVal(d, he); // 再释放 value
- zfree(he); // 最后释放 entry
- ht->used--;
- he = nextHe;
- }
- }
- /* Free the table and the allocated cache structure */
- zfree(ht->table); // 可以回收第一维数组了
- /* Re-initialize the table */
- _dictReset(ht);
- return DICT_OK; /* never fails */
- }
这些代码散落在多个不同的文件,我将它们凑到了一块便于读者阅读。从代码中我们可以看到释放一个对象要深度调用一系列函数,每种对象都有它独特的内存回收逻辑。
04.5.9.4 队列安全 (编辑:晋中站长网)
【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!
|