当对象在内存中移动时,指针如何保持有效?

时间:2016-02-12 16:09:45

标签: c pointers memory

想象一下,在C中我在堆上分配了两个结构。其中一个结构有一个字段,它保存指向另一个结构的指针。

据我所知,堆中的数据可能会移动,因此事物的地址会发生变化。例如,可能会发生堆上的碎片整理,将第二个结构移动到堆中的其他位置。

这有助于理解我在说什么 https://en.m.wikibooks.org/wiki/Memory_Management/Memory_Compacting

这个结构的重点现在是错误的(即保存错误的内存地址)。

我并不是说这个问题特定于C,而是更一般:在任何时候,平台都可能决定移动事物。指针如何保持有效?

3 个答案:

答案 0 :(得分:14)

这里的关键概念是virtual memory。您的指针不指向物理地址,而是指向进程的虚拟地址空间中的虚拟地址。你所说的是正确的,数据可能会被移动,甚至交换到磁盘,然后再次映射到物理内存到另一个帧,但指针所指向的虚拟地址始终保持不变。

答案 1 :(得分:4)

当你在C中看到一个指针时,你会发现看起来像内存地址的东西,但实际上,在这个和物理内存地址之间会有一个(如果不是两个)抽象层次。

这不仅有助于提高操作系统的安全性,还可以执行任何碎片任务(无论它们是什么),而无需更改C程序观察到的内容。

答案 2 :(得分:4)

C标准不允许实现(自发地)以使现有指针无效的方式移动。可能存在一个实现" defragment"堆,但我不知道任何实现。

我自发地说""因为代码中的realloc()调用实际上可能导致对象移动;这就是realloc返回指针的原因。如果realloc返回的指针与原始指针不同,则原始指针(以及任何别名指针)都无效。但这是您必须在自己的代码中跟踪的内容。

托管语言(Java,C#,Python,无论如何)可以(或可能不)通过添加额外级别的间接和/或跟踪指向堆的指针来处理堆碎片。这样,当X移动到不同的位置时,语言运行库可以更新对象X的所有指针。这将由垃圾收集系统处理。

对于提供垃圾收集器的C实现来说,有些不寻常,并且可能无法以符合标准的方式完成,因为您可以(安全地)执行所有操作用指针。因此,您的问题的前提是堆可能会被实现自发地进行碎片整理,这是无效的。