我最近一直在阅读一系列自动内存管理技术,这些技术依赖于在分配器返回的指针中存储信息,即标题的少量位,例如区分指针或存储线程相关信息(请注意,我不是在谈论有限字段引用计数,只是不可变信息)。
我想玩这些技巧。现在,为了实现它们,我需要能够从我的分配器返回具有特定形状的指针。我想我可以用最轻的比特来玩,但这需要填充看起来非常耗费内存,所以我相信我应该玩最重的比特。但是,我不知道如何做到这一点。有没有办法让我,调用malloc
或malloc_create_zone
或一些相关的函数,并请求一个始终以给定位开头的指针?
谢谢大家!
答案 0 :(得分:2)
您实际可以存储在指针中的信息量非常有限(通常每个指针有一位或两位)。每次取消引用指针的尝试都必须首先掩盖魔法信息。该技术通常称为tagging,BTW。
#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个字节),所以最少有效位始终为零。