6

我设法通过

GCHandle objHandle = GCHandle.Alloc(obj,GCHandleType.WeakTrackResurrection);
int address = GCHandle.ToIntPtr(objHandle).ToInt32();  

我可以通过

Object obj = GCHandle.FromIntPtr(IntPtr(address)).Target;

好吧,目的是将地址存储在本机类中,并具有有关哪个本机对象与哪个 .net 对象相关的信息。
AFAIK地址不会因为分配而改变,这是真的还是有人有更好的主意来服务我的目的?

谢谢

4

4 回答 4

7

您需要固定 GCHandle 以阻止对象四处移动,因为 GC 会移动对象,因此未固定的指针可能会变得无效。固定对象使其停止移动:

GCHandle handle = GCHandle.Alloc(obj, GCHandleType.Pinned);
IntPtr ptr = handle.AddrOfPinnedObject();

完成后,您还必须释放手柄:

handle.Free();
于 2010-11-04T13:20:20.053 回答
6

正如 Tim 和 thecoop 所指出的, GCHandle.Alloc 可能会阻止垃圾收集,但实际对象地址可能会发生变化,因为 GC 可能会移动对象,除非您固定对象。此外,您的代码正在使用GCHandleType.WeakTrackResurrection并且不会阻止垃圾收集。GCHandle.ToIntPtr将给出可以通过非托管调用往返的句柄地址。实际对象地址将由AddrOfPinnedObject方法给出。

说了这么多,IMO,您的代码可能用于将 .NET 对象与非托管对象相关联。这是因为 GCHandle.To/FromIntPtr 将返回正确的 GCHandle 并且您可以通过它访问您的 .NET 对象(前提是它没有被垃圾收集)。IMO,实际对象地址是否已更改应该无关紧要。

于 2010-11-04T13:31:03.997 回答
2

你得到的实际上并不是一个地址。

正如您所注意到的,它在大多数情况下似乎就像一个地址,您可以通过使用 GCHandle.FromIntPtr 来调用该对象。但是,有趣的问题是您正在使用GCHandleType.WeakTrackResurrection

如果你的弱引用对象被收集(它可能可以,因为它只是被 GCHandle 弱引用),你仍然有 IntPtr,你可以将它传递给GCHandle.FromIntPtr()。如果你这样做了,那么你会返回 null,假设 IntPtr 没有被回收。

(如果 IntPtr 由于某种原因被 CLR 回收了,那么你就有麻烦了。我不确定这是否会发生。)

如果您想要对对象的强引用,最好使用GCHandleType.NormalGCHandleType.Pinned(如果您需要在非托管代码中获取对象的地址)。

(要使用 GCHandleType.Pinned,您的对象必须是原始的,或者具有 [StructLayout] 属性,或者是此类对象的数组。)

于 2011-01-19T00:26:56.873 回答
1

AFAIK地址不会因为分配而改变,是真的吗

托管对象的地址确实发生了变化。垃圾收集器可以自由移动内存中的对象。当垃圾收集器运行时,它会收集未使用的对象,然后重新排列剩余的对象以最小化托管堆的整体大小。

有没有人有更好的主意来服务我的目的?

我不确定您是否会找到一种长时间保持托管对象指针的好方法。可以将对象固定在内存中,并以这种方式获取它们的地址,但在 C# 中,只能在单个方法中固定对象。

如果您更详细地解释一旦有了指针您将如何处理它,将会有所帮助。

于 2010-11-04T13:20:12.470 回答