将相同的内存(mmap
在 Ignacio 提到的 POSIX 上,MapViewOfFile
在 Windows 上)映射到多个虚拟地址可能会为您提供一些有趣的一致性难题(在另一个地址读取时,在一个地址上的写入是否可见?)。或者可能不是。我不确定所有平台保证是什么。
更常见的是,只需在指针中保留几位,并根据需要进行移位。
如果您的所有对象都与 8 字节边界对齐,则通常只需将标签存储在指针的 3 个最低有效位中,并在取消引用之前将它们屏蔽掉(如 thkala 所述)。如果选择更高的对齐方式,例如 16 字节或 32 字节,则有 3 或 5 个最低有效位可用于标记。等效地,选择一些最重要的位进行标记,并在取消引用之前将它们移开。(有时会使用非连续位,例如,当将指针打包到 IEEE-754 浮点数(2 23个值)或双精度数(2 51 个值)的信令 NaN 中时。)
继续指针的高端,x86-64 的当前实现最多使用 64 位指针中的 48 位(0x0000000000000000-0x00007fffffffffff + 0xffff800000000000-0xffffffffffffffff),Linux 和 Windows 仅将第一个范围内的地址分发给用户空间,留下 17 个最重要的位可以安全地屏蔽掉。(不过,这既不是可移植的,也不能保证在未来保持真实。)
另一种方法是停止考虑“指针”,而只是将索引用于更大的内存数组,就像 JVM 对-XX:+UseCompressedOops
. 如果您分配了一个 512MB 的池并存储 8 字节对齐的对象,则有 2 26个可能的对象位置,因此除了索引之外,32 值还有 6 位可用。取消引用将需要将索引乘以对齐到数组的基地址,并保存在其他位置(每个“指针”都相同)。如果您仔细观察,这只是对先前技术的概括(其基数始终为 0,事物与实际指针对齐)。