获取.NET对象的内存地址(C#)

我试图追踪单声道运行时中的一个错误,其中变量似乎被分配给一个有效对象,然后被重新分配给一个虚假对象,特别是

//early in code I allocate, fine var o = new object(); // valid allocation // later in code this is called, not fine lock(o) // <- is triggering bug due to "o" now referencing a nonsense memory location. 

我想知道何时对“o”的引用变得无意义,并且这样做是为了找到一种方法来确定C#代码中不同时间点的“o”的地址。 我知道类似于其他问题的答案“不要那样做有GC”,但GC不起作用所以我需要一个解决方法。

有谁知道如何确定C#中单声道对象的地址? 很好地链接在非托管代码或其他任何东西。 (关于诊断主要问题的方法的任何其他线索)。

您应该能够使用GCHandle构造来完成此任务。

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

‘obj’是你想要得到的地址的对象。

事实certificate这在.NET中是不可能的,但可以通过改变单声道运行时代码来实现。 要创建可以读取内存地址的C#方法,请对单声道源代码进行以下更改:

更改gc-internal.h

 gpointer ves_icall_System_GCHandle_GetAddrOfObject (MonoObject *obj) MONO_INTERNAL; 

改变gc.c添加:

 gpointer ves_icall_System_GCHandle_GetAddrOfObject (MonoObject *obj) { return (char*)obj; } 

改变GCHandle.cs添加:

 MethodImplAttribute(MethodImplOptions.InternalCall)] private extern static IntPtr GetAddrOfObject(object obj); public static IntPtr AddrOfObject(object o) { IntPtr res = GetAddrOfObject(o); return res; } 

改为添加icall-def.h

 ICALL(GCH_6, "GetAddrOfObject", ves_icall_System_GCHandle_GetAddrOfObject) 

请注意,这些必须按顺序排列,因此请将其添加到GetAddrOfPinnedObject行重建之上

最后,从C#调用它

 for (int i = 0; i < 100; i++) { object o = new object (); var ptr = GCHandle.AddrOfObject (o); Console.WriteLine ("Address: " + ptr.ToInt64().ToString ("x")); } 

通常,您无法在托管代码中获取已管理对象的地址。 如果对象有一个类似int的字段,你可以使用固定的C#语句获取它的地址,然后在对象内部有一个指针。 出于调试目的,您可以做出一些假设并获得对象的基指针的偏移量(在32位平台上,单声道上的对象头大小为8字节,此时64位架构上为16字节)。

您的错误报告声称您正在使用Boehm收集器,并且该收集器不会在内存中移动对象,该错误可能是由于某些不相关的内存损坏,对象被错误释放或GC中的其他逻辑错误引起的(我不确定你指出的零大小是否相关,因为托管对象至少有8-16字节的标头)。

我的替代品……还有@ 这个类似的问题

 #region AddressOf ///  /// Provides the current address of the given object. ///  ///  ///  [System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)] public static System.IntPtr AddressOf(object obj) { if (obj == null) return System.IntPtr.Zero; System.TypedReference reference = __makeref(obj); System.TypedReference* pRef = &reference; return (System.IntPtr)pRef; //(&pRef) } ///  /// Provides the current address of the given element ///  ///  ///  ///  [System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)] public static System.IntPtr AddressOf(T t) //refember ReferenceTypes are references to the CLRHeader //where TOriginal : struct { System.TypedReference reference = __makeref(t); return *(System.IntPtr*)(&reference); } [System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)] static System.IntPtr AddressOfRef(ref T t) //refember ReferenceTypes are references to the CLRHeader //where TOriginal : struct { System.TypedReference reference = __makeref(t); System.TypedReference* pRef = &reference; return (System.IntPtr)pRef; //(&pRef) } ///  /// Returns the unmanaged address of the given array. ///  ///  ///  if null, otherwise the address of the array [System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)] public static System.IntPtr AddressOfByteArray(byte[] array) { if (array == null) return System.IntPtr.Zero; fixed (byte* ptr = array) return (System.IntPtr)(ptr - 2 * sizeof(void*)); //Todo staticaly determine size of void? } #endregion 
Interesting Posts