C++CLI marshal_context本机字符串已损坏

问题描述 投票:-1回答:1

以下是C++CLI代码被编译成DLL,并被C#应用程序调用。

void Foo(String^ strManaged) {
    marshal_context^ context = gcnew marshal_context();
    FooUnmanaged(context->marshal_as<const char*>(strManaged));
}

FooUnmanaged() 读取 const char*,运行一些处理,大约需要一秒钟,然后读取 const char* 再比如,。

void FooUnmanaged(const char* str) {
    // 1
    Log(str);

    // Process things unrelated to 'str'
    // ...

    // 2
    Log(str);
}

在某些情况下... str 读取的第一和第二之间的变化 FooUnmanaged()就像该内存被重新用于其他用途一样。无论在 FooUnmanaged()只要它需要一个明显的时间量(我想,足够长的时间让GC有机会触发)。

这种情况不会发生,如果 Foo 要么这样写

void Foo(String^ strManaged) {
    marshal_context^ context = gcnew marshal_context();
    FooUnmanaged(context->marshal_as<const char*>(strManaged));
    delete context; // addded
}

或者那样

void Foo(String^ strManaged) {
    marshal_context context; // created on the stack
    FooUnmanaged(context.marshal_as<const char*>(strManaged));
}

原代码是否有误?为什么它不能正确地预留出内存的 const char* 终身 context? 或者说,可以用一生的时间 context 比我想象中的要短(的范围)。Foo())?

string memory c++-cli marshalling
1个回答
0
投票

由 @HansPassant 提供的答案。

是的,这是一个终身问题。.NET使用了一个激进的收集器,它不知道本地代码依赖于上下文。第一个片段需要 GC::KeepAlive(context); 在最后。最后一个片段是如何使用的,堆栈语义效仿RAII,自动生成的 Dispose() 调用以类似的方式保持其活力。并且避免了临时的内存泄漏。如果 FooUnmanaged() 存储传递的指针,那么你就不能使用 marshal_context.

这一点得到了证实。本文:

局部变量】的寿命可能取决于程序的构建方式。在调试构建中,只要方法在堆栈中,局部变量就会持续存在。在发行版构建中,JIT能够查看程序结构,计算出变量在执行过程中可以被方法使用的最后一点,并在不再需要它时将其丢弃。

© www.soinside.com 2019 - 2024. All rights reserved.