Valkey源码剖析(18):对象引用计数

Valkey服务器通过对象的引用计数特性来管理其自行创建的对象,其中对象的计数值就记录在server.h/serverObject结构的refcount属性中:

struct serverObject {

    // ...

    // 引用计数
    unsigned refcount : OBJ_REFCOUNT_BITS;

    // ...
};

举个例子,当Valkey服务器在运行过程中需要创建一个对象以保存某项信息的时候,它通常会调用相应的对象构造函数,这些函数会将对象的refcount设置为1。

之后,如果服务器内有其他调用者需要用到刚刚创建的对象,那么服务器将调用object.c/incrRefCount()函数以增加相应对象的引用计数,比如把计数值从1增加为2,等等:

void incrRefCount(robj *o) {
    if (o->refcount < OBJ_FIRST_SPECIAL_REFCOUNT) {
        // 正常对计数增一
        o->refcount++;
    } else {
        // 处理特殊对象(它们无法增加计数)
        if (o->refcount == OBJ_SHARED_REFCOUNT) {
            /* Nothing to do: this refcount is immutable. */
        } else if (o->refcount == OBJ_STATIC_REFCOUNT) {
            serverPanic("You tried to retain an object allocated in the stack");
        }
    }
}

在此之后,每个调用者将对对象做相应的处理,并在使用完对象之后,调用object.c/decrRefCount()函数以减少对象的引用计数。当对象的计数值降低至0的时候,decrRefCount()函数将调用相应的对象析构函数以自动释放对象:

void decrRefCount(robj *o) {
    if (o->refcount == 1) {
        // 当引用计数降为0的时候,释放对象
        if (o->ptr != NULL) {
            // 基于对象的类型调用不同的对象析构函数
            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;
            case OBJ_MODULE: freeModuleObject(o); break;
            case OBJ_STREAM: freeStreamObject(o); break;
            default: serverPanic("Unknown object type"); break;
            }
        }
        zfree(o);
    } else {
        // 如果对象当前的引用计数大于1,那么将其计数减一
        if (o->refcount <= 0) serverPanic("decrRefCount against refcount <= 0");
        if (o->refcount != OBJ_SHARED_REFCOUNT) o->refcount--;
    }
}

以上就是Valkey通过引用计数技术管理对象生命周期的原理。

黄健宏
2026.1.12