GCHandle获取.net对象的地址(指针)
我设法获取了 .net 对象的地址,
GCHandle objHandle = GCHandle.Alloc(obj,GCHandleType.WeakTrackResurrection);
int address = GCHandle.ToIntPtr(objHandle).ToInt32();
并且我可以通过 调用该对象
Object obj = GCHandle.FromIntPtr(IntPtr(address)).Target;
好吧,目的是将地址存储在本机类中,并获得哪个本机对象与哪个 .net 对象相关的信息。
据我所知,地址不会因为分配而改变,这是真的还是有人有更好的主意来达到我的目的?
谢谢
I managed to get the address of a .net object by
GCHandle objHandle = GCHandle.Alloc(obj,GCHandleType.WeakTrackResurrection);
int address = GCHandle.ToIntPtr(objHandle).ToInt32();
and I can recall the object by
Object obj = GCHandle.FromIntPtr(IntPtr(address)).Target;
Well, the purpose is to store the address in a native class and have an information of which native object is releated to which .net object.
AFAIK the address does not change because of allocing, is it true or does anyone have a better idea to serve my purpose?
Thanks
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
正如 Tim 和 thecoop 所指出的,GCHandle.Alloc 可能会阻止垃圾回收,但实际的对象地址可能会发生变化,因为 GC 可能会移动对象,除非您固定该对象。此外,您的代码正在使用 GCHandleType.WeakTrackResurrection,这不会阻止垃圾收集。 GCHandle.ToIntPtr 将给出可以通过非托管调用进行往返的句柄地址。实际的对象地址将由
AddrOfPinnedObject
方法给出。综上所述,IMO,您的代码可能用于将 .NET 对象与非托管对象关联起来。这是因为 GCHandle.To/FromIntPtr 会返回正确的 GCHandle,并且您可以通过它访问您的 .NET 对象(前提是它没有被垃圾收集)。 IMO,实际对象地址是否更改应该无关紧要。
As Tim and thecoop has pointed out, GCHandle.Alloc may prevent garbage collection but actual object address can change as GC may move object around unless you pin the object. Further, your code is using
GCHandleType.WeakTrackResurrection
and that would not event prevent the garbage collection.GCHandle.ToIntPtr
will give address of handle that can be round-tripped over unmanaged call. Actual object address will be given byAddrOfPinnedObject
method.Said all that, IMO, your code may serve the purpose of associating .NET object with unmanaged object. This is because GCHandle.To/FromIntPtr will get back you correct GCHandle and you can reach your .NET object via it (provided its not garbage collected). IMO, it should be immaterial if actual object address had changed or not.
当 GC 移动对象时,您需要固定 GCHandle 以阻止对象移动,因此未固定的指针可能会变得无效。固定对象会使其停止移动:
完成后,您还必须释放手柄:
You'll want to pin the GCHandle to stop the object moving around, as the GC moves objects around, so an unpinned pointer could become invalid. Pinning the object stops it moving:
You'll also have to free the handle when you're done:
您得到的实际上并不是地址。
正如您所注意到的,大多数时候它看起来就像一个地址,您可以通过使用 GCHandle.FromIntPtr 来调用该对象。然而,有趣的问题是您正在使用GCHandleType.WeakTrackResurrection。
如果您的弱引用对象被收集(大概可以,因为它仅被 GCHandle 弱引用),您仍然拥有 IntPtr,并且可以将其传递给 GCHandle.FromIntPtr()。如果这样做,那么您将返回 null,假设 IntPtr 尚未被回收。
(如果 IntPtr 由于某种原因被 CLR 回收,那么您就有麻烦了。我不确定这是否会发生。)
您最好使用 GCHandleType.Normal 或 < strong>GCHandleType.Pinned(如果您需要在非托管代码中获取对象的地址),如果您想要对该对象的强引用。
(要使用 GCHandleType.Pinned,您的对象必须是原始对象,或者具有 [StructLayout] 属性,或者是此类对象的数组。)
What you are getting is not actually an address.
As you notice, it seems to act like an address most of the time, and you can recall the object, by using GCHandle.FromIntPtr. However, the interesting issue is that you are using GCHandleType.WeakTrackResurrection.
If your weakly referenced object gets collected (it presumably can, since it is only weakly referenced by the GCHandle), you still have the IntPtr, and you can pass it to GCHandle.FromIntPtr(). If you do so, then you get back null, assuming the IntPtr has not been recycled.
(If the IntPtr has been recycled by the CLR for some reason, then you are in trouble. I'm not sure whether this can happen.)
You are better off using either GCHandleType.Normal, or GCHandleType.Pinned (if you need to take the address of the object in unmanaged code), if you want a strong reference to the object.
(To use GCHandleType.Pinned, your object must e.g. be primitive, or have [StructLayout] attribute, or be an array of such objects.)
托管对象的地址确实发生了变化。垃圾收集器可以自由地移动内存中的对象。当垃圾收集器运行时,它会收集未使用的对象,然后重新排列剩余的对象以最小化托管堆的总体大小。
我不确定您是否会找到一种好方法来长时间保留托管对象的指针。可以将对象固定在内存中,并以这种方式获取它们的地址,但在 C# 中,只能在单个方法中固定对象。
如果您更详细地解释获得指针后将如何使用它,将会有所帮助。
The address of a managed object does change. The garbage collector is free to move objects in memory. When the garbage collector runs, it collects unused objects, then rearranges the remaining objects to minimize the overall size of the managed heap.
I'm not sure you'll find a good way to keep hold of a pointer for a managed object for long periods of time. It's possible to pin objects in memory, and get their address that way, but in C# it's possible to pin objects only within a single method.
It would help if you explained in more detail what you're going to do with the pointer once you have it.