【问题标题】:Marshal::GetFunctionPointerForDelegate: should I release its result?Marshal::GetFunctionPointerForDelegate: 我应该发布它的结果吗?
【发布时间】:2013-05-13 15:55:33
【问题描述】:

我正在将托管 System.Action 转换为 C++/CLI 项目中的非托管 std::function;我应该在使用回调后释放给定的 IntPtr,还是没有必要?

void MyClass::Execute(System::Action^ callback)
{           

    IntPtr callbackPtr = Marshal::GetFunctionPointerForDelegate(callback);
    std::function<void (void)> nativeCallback = static_cast<void (__stdcall *) (void)>(callbackPtr.ToPointer());

    m_nativeObject->Execute(wrappedCallback);

    // should I release callbackPtr here?
}

【问题讨论】:

    标签: c# lambda c++-cli std-function


    【解决方案1】:

    没有。没有 Marshal 类方法可以做到这一点。与所有动态生成的代码一样,此方法创建的 thunk 与 AppDomain 相关联,并在 AppDomain 卸载时被卸载。

    请注意,委托对象并非如此,它受制于正常的垃圾收集规则。而且您必须小心,thunk 不会让它保持活力。这是您的代码中的一个错误,可以在本机代码忙于执行时收集委托。您需要将这行代码添加到方法的末尾:

    GC::KeepAlive(callback);
    

    假设只有在执行 Execute() 方法时才会进行回调。如果非托管代码在此方法调用之外存储了函数指针,那么您必须将委托对象存储在某处以保持其有效。

    【讨论】:

    • 即使 m_nativeObject->Execute(wrappedCallback) 是同步的?
    • 那是我第一次看到 GC.KeepAlive 有任何用处。
    【解决方案2】:

    不,但是如果您调用 Alloc 在回调委托上创建 GCHandle,则必须使用 GCHandle.Free() 释放该句柄。 这是一篇很好的文章,包括如何防止 GC 过早地处理您的委托: http://msdn.microsoft.com/en-us/library/367eeye0%28v=VS.100%29.aspx

    【讨论】:

      【解决方案3】:

      您不需要释放指针。 您已经有了指向该函数的指针(根据您的机器架构,它是 32/64 位大小)。如果 .net 框架基础结构需要更多的东西来运行指针,那么它对于所有方法都是相同的,因此它将被静态分配(无状态)。

      【讨论】:

      • 我认为这不是真的。例如,GetFunctionPointerForDelegate 可以为同一个 lambda 返回不同的值,因为 lambda 可以捕获数据,并且对于不同的实例,数据可能不同,即使 lambda 的代码是恒定的。我对此感到惊讶,但与 C 代码交互时非常方便 - 我的回调可以访问捕获的数据。
      • @avl_sweden:你可以有来自同一个 lambda 的不同委托实例,但状态完全编码在委托实例中;每个委托实例只有一个函数指针就足够了。
      • 啊哈,每个闭包调用都有自己的委托实例吗?
      猜你喜欢
      • 2017-03-10
      • 1970-01-01
      • 1970-01-01
      • 2015-11-10
      • 1970-01-01
      • 1970-01-01
      • 2012-02-16
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多