如何处理在方法中间在内存中移动的对象?
How do I handle an object moving in memory in the middle of a method?
我正在用c++为编程语言编写一个VM。这种语言是垃圾收集的,所以我在垃圾收集堆中分配了c++类的实例。我正在使用复制收集器,因此当发生GC时,这些对象将被移动到内存中。这意味着指向该对象的每个指针都需要更新。大多数都很容易处理,除了一个棘手的:this
。考虑:
class SomeObj : public Managed // inheriting from this means it's on the GC heap
{
public:
void method()
{
SomeObj* other = new SomeObj(); // could trigger a GC.
printf("%dn", someField); // this points to wrong memory
}
private:
int someField;
};
如果我在GC堆上的某个对象的实例方法的中间,那么this
指向一些GC内存。收集可以发生在此方法的中间。当这种情况发生时,对象被移动到一个新的位置。但是,由于我们处于方法调用的中间,this
仍然指向旧的错误位置。
我可以通过不在托管内存中的类上使用实例方法来解决这个问题,但我确实喜欢这样的代码更简单。有什么技巧可以解决这个问题吗?
您的GC需要扫描堆栈和寄存器中的指针并修复它们。如果您的VM支持多线程,则需要在扫描它们的堆栈时挂起所有线程。this指针将位于堆栈上或寄存器中。
由于c++不提供堆栈的类型信息,因此使用
这样的内容可能会很困难。int i = 1000000;
char * p = new char[10]; // 0xF4240 = 1000000
无论你用什么方法来移动其他指针都会有同样的问题。在某些时候,你的代码必须将句柄转换为指针,这些指针将需要修复。
像这样修改c++代码
func()->method()
看起来像
struct GCroot call123 = { func() };
call123.obj->method();
多线程问题。如果你有这样的代码
struct GCroot obj123 = { /* .. */ };
obj123.ptr->x = obj123.ptr->x + 1;
它可能生成如下的伪汇编代码
load r1, obj123.ptr
load r2, (r1)
add r2, 1
store (r1), r2
如果另一个线程在第一个和最后一个asm行之间的任何时间做GC, r1如何得到修复?
您可以引入另一个间接层次。我将使用你的例子:
class SomeData : public Managed
{
int someField;
};
class SomeObj : public Managed // inheriting from this means it's on the GC heap
{
public:
void method()
{
SomeObj* other = new SomeObj(); // could trigger a GC.
printf("%dn", someData->someField); // this points to wrong memory
}
private:
SomeObjData* someData;
};
相关文章:
- 如何在窗口之间移动 std::unique_ptr 而不会冒内存泄漏的风险?
- vector是否为std::移动的对象连续分配内存
- 垃圾回收正在移动内存中被引用的对象,破坏Unreal4引擎中的引用
- 在预分配的内存中移动数据
- 导入的库函数是否可以在内存中移动
- 内存移动的性能与memcpy相比是两倍?
- 在数组中移动一系列元素,无需额外内存
- 将函数移动到线程(使用 lambda)时内存泄漏
- 使用STD ::移动时的内存泄漏
- C 指向对象,然后移动其内存位置
- 从字符串和向量移动以不拥有任何堆内存
- memmove会移动元素(就像前面的方式相同),还是一次抓住整个内存块
- C 可以在程序执行过程中移动内存映射的文件(boost :: intercecess)移动
- 将指针移动到其他位置后删除分配的内存
- 将 SQL 数据库移动到内存中
- int类型的指针在递增后移动内存中的1个地址
- 如何将对象移动到未初始化的内存中
- C++在内存中逐字节移动
- 使用内存移动构造函数
- 在字符指针中用内存移动替换字符