将内存映射到另一个地址

时间:2012-06-02 06:10:49

标签: c memory

X86-64,Linux,Windows。

考虑一下,我想做一些“免费启动标记指针”。基本上我想要有两个指针指向相同的实际内存块但其位不同的指针。 (例如,我希望GC集合使用一个位或出于其他原因)。

intptr_t ptr = malloc() 
intptr_t ptr2 = map(ptr | GC_FLAG_REACHABLE) //some magic call

int* p = int*(ptr);
int* p2 = int*(ptr2);
*p = 10;
*p2 = 20;
assert(*p == 20)
assert(p != p2)

3 个答案:

答案 0 :(得分:2)

在Linux上,mmap()两次使用相同的文件。在Windows上也是如此,但它有自己的一套功能。

答案 1 :(得分:2)

将相同的内存(在Ignix上提及的mmap(在Windows上为MapViewOfFile)映射到多个虚拟地址可能会为您提供一些有趣的一致性谜题(在另一个地址读取时可以在一个地址写入?)。或者可能不是。我不确定所有平台保证是什么。

更常见的是,只需在指针中保留几个位并根据需要移动。

如果所有对象都与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为基础,其中的东西与实际指针对齐)。

答案 2 :(得分:1)

曾几何时我在Prolog实现上使用了以下技术在指针中有备用位:

  • 使用已知对齐方式分配内存区域。 malloc()通常使用4字节或8字节对齐分配内存。如有必要,请使用posix_memalign()获取具有更高对齐大小的区域。

  • 由于生成的指针与多个字节的间隔对齐,但它表示字节精确的地址,因此您有一些备用位,根据定义,它们在内存区域指针中为零。例如,4字节对齐为您提供指针LSB侧的两个备用位。

  • 你或(|)你的标志与这些位,现在有一个标记指针。

  • 只要你在使用它进行内存访问之前注意正确地屏蔽指针,你应该完全没问题。