【问题标题】:Where do I put GC.KeepAlive?我在哪里放置 GC.KeepAlive?
【发布时间】:2019-03-27 21:44:26
【问题描述】:

我需要在非托管代码中注册回调,但看起来 GC 一直在收集我的引用。所以我添加了GC.KeepAlive(callback_pin);,但它没有效果。我不知道应该把GC.KeepAlive放在哪里。

这是我将自己的回调注册到非托管事件的代码,它是从线程调用的。 (Some_Callback 和 Some_Method 是外部对象)

var callback_pin = new Some_Callback(MyManagedCallback);
GC.KeepAlive(callback_pin);
Some_Method(callback_pin);
return true;

下面是我如何导入非托管代码。随附的文档建议我使用上述代码来保持回调有效,但由于在我的情况下从未触发回调,因此我认为这不是正确的方法。有什么启示吗?

[UnmanagedFunctionPointer(CallingConvention.StdCall, CharSet = CharSet.Unicode)]
public delegate void Some_Callback(Int32 line, [MarshalAs(UnmanagedType.LPWStr)] string msg);

[DllImport("SOME_DLL.dll", CharSet = CharSet.Unicode)]
public static extern Int32 Some_Method(MulticastDelegate funcPtr, Int32 mask);

【问题讨论】:

  • 你试过把它放在例行程序的末尾吗?
  • @JoeSewell 还没有,但我马上试试
  • @JoeSewell 我试过了,但没有任何影响
  • 您提到回调是“已处置”的-您的意思是某事在其上调用Dispose?这与垃圾收集不同。如果回调对象在非托管代码使用它之前被释放,该对象仍然存在于内存中,但非托管代码可能无法使用该对象,具体取决于对象被释放的语义。
  • 一个keepalive保持引用存活直到keepalive,所以它必须去last,并且允许root在最后一个之后立即消失活着。但是就是说,您没有提供任何证据表明您的问题是 GC 正在收集您的委托。您的症状是没有调用代表。如果它在被非托管代码调用之前就被收集了,那么您可能会使运行时崩溃。弄清楚谁应该打电话给代表以及为什么不打电话。

标签: c# garbage-collection unmanaged


【解决方案1】:

在它们作为参数参与的本机函数的持续时间内,委托会自动“保持活跃”(技术术语是“根”)。

如果您调用的本机函数仅存储指针,那么您只需要特殊代码来保持它们的活动状态,然后稍后另一个函数(或线程)使用存储的指针。到那时,该框架可能会垃圾收集您的委托。

此外,您的问题有所不同,如果委托被垃圾收集,您在调用它时会遇到访问冲突。如果什么都没发生,您的本机函数根本就没有调用它——调试它!

【讨论】:

  • 感谢您的解释,是的,它应该是别的东西,因为我没有收到任何错误。如果我有源代码,我会调试它,但我试图猜测幕后发生的事情,并弄清楚供应商建议使用 keepAlive 是什么意思。
  • 那么你就是个 SOL,这肯定是一个与 API 相关的问题,而且由于我们不知道你的 API,我们可能无法帮助你。
  • 我不希望他们知道答案,所以我必须首先确保我对这个主题的理解足够好。感谢您的帮助:-)
猜你喜欢
  • 1970-01-01
  • 2011-07-16
  • 2012-04-04
  • 2023-03-22
  • 2021-02-20
  • 2020-04-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多