GCHandle获取.net对象的地址(指针)

时间:2010-11-04 13:15:49

标签: c# .net pointers memory-management memory-address

我设法通过

获取.net对象的地址
GCHandle objHandle = GCHandle.Alloc(obj,GCHandleType.WeakTrackResurrection);
int address = GCHandle.ToIntPtr(objHandle).ToInt32();  

我可以通过

回忆起这个对象
Object obj = GCHandle.FromIntPtr(IntPtr(address)).Target;

好吧,目的是将地址存储在本机类中,并获取哪个本机对象与哪个.net对象相关联的信息。
AFAIK地址不会因为分配而改变,是真的还是有人有更好的想法来实现我的目的?

由于

4 个答案:

答案 0 :(得分:6)

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

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

完成后你还必须释放手柄:

handle.Free();

答案 1 :(得分:5)

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

所有这一切,IMO,您的代码可能用于将.NET对象与非托管对象相关联。这是因为GCHandle.To/FromIntPtr将返回正确的GCHandle,您可以通过它访问您的.NET对象(前提是它不是垃圾回收)。 IMO,如果实际对象地址发生了变化,那应该是无关紧要的。

答案 2 :(得分:2)

你得到的不是一个地址。

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

如果您的弱引用对象被收集(可能是因为它只被GCHandle弱引用),您仍然拥有IntPtr,并且可以将其传递给 GCHandle.FromIntPtr() 。如果这样做,那么假设IntPtr尚未被回收,则返回null。

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

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

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

答案 3 :(得分:1)

  

AFAIK地址因分配而没有改变,是真的吗

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

  

有没有人有更好的想法来实现我的目的?

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

如果您更详细地解释了一旦拥有指针将会对您做什么,这会有所帮助。