我最近读到一系列自动内存管理技术,这些技术依赖于在分配器返回的指针中存储信息,即头的几个位,例如区分指针或存储与线程相关的信息(注意,我在这里不是在谈论有限字段引用计数,只是不可变信息)。
我喜欢玩弄这些技巧。现在,为了实现它们,我需要能够从分配器返回具有特定形状的指针。我想我可以使用最小权重的位,但这将需要填充,看起来非常消耗内存,所以我认为我应该使用最重的位。然而,我对如何做到这一点没有好主意。我是否有一种方法,调用malloc
或malloc_create_zone
或一些相关的函数,并请求一个指针,总是以给定的位开始?
谢谢大家!
实际上可以在指针中存储的信息量是非常有限的(每个指针通常是1或2位)。而且每次对指针解引用的尝试都必须首先屏蔽掉魔术信息。顺便说一句,这种技术通常被称为标记。
#define TAG_MASK 0x3
#define CONS_TAG 0x1
#define STRING_TAG 0x2
#define NUMBER_TAG 0x3
typedef uintptr_t value_t;
typedef struct cons {
value_t car;
value_t cdr;
} cons_t;
value_t
create_cons(value_t t1, value_t t2)
{
cons_t* pair = malloc(sizeof(cons_t));
value_t addr = (value_t)pair;
pair->car = t1;
pair->cdr = t2;
return addr | CONS_TAG;
}
value_t
car_of_cons(value_t v)
{
if ((v % TAG_MASK) != CONS_TAG) error("wrong type of argument");
return ((cons_t*) (v & ~TAG_MASK))->car;
}
这种技术的一个优点是,可以直接从指针本身推断对象的类型。您不需要对其解引用(例如,为了读取特殊的type
字段或类似内容)。许多使用这种方案的语言实现也有一个特殊的标记组合,用于"即时"数字和其他小值,这些值可以直接使用"指针"表示。
缺点是,可以存储的信息量非常有限。此外,正如示例代码所示,您必须注意每次访问对象时的标记,并且需要在实际使用指针之前"取消"它。
根据观察,在大多数平台上,所有指向malloc
内存的指针实际上都对齐在非字节边界上(通常为8字节),因此最低有效位始终为零。