gpt4 book ai didi

c# - C#中对象的内存地址

转载 作者:IT王子 更新时间:2023-10-29 03:43:49 25 4
gpt4 key购买 nike

我有一个前段时间写的函数(for .NET 3.5),现在升级到4.0了

我无法让它工作。

函数是:

public static class MemoryAddress
{
public static string Get(object a)
{
GCHandle handle = GCHandle.Alloc(a, GCHandleType.Pinned);
IntPtr pointer = GCHandle.ToIntPtr(handle);
handle.Free();
return "0x" + pointer.ToString("X");
}
}

现在,当我调用它时 - MemoryAddress.Get(new Car("blue"))

public class Car
{
public string Color;
public Car(string color)
{
Color = color;
}
}

我得到错误:

Object contains non-primitive or non-blittable data.

为什么它不再起作用了?

现在如何获取托管对象的内存地址?

最佳答案

您可以使用 GCHandleType.Weak 而不是固定。另一方面,还有另一种获取对象指针的方法:

object o = new object();
TypedReference tr = __makeref(o);
IntPtr ptr = **(IntPtr**)(&tr);

需要不安全的 block ,非常非常危险,根本不应该使用。 ☺


在 C# 中无法使用 by-ref locals 的那一天,有一种未记录的机制可以完成类似的事情 – __makeref

object o = new object();
ref object r = ref o;
//roughly equivalent to
TypedReference tr = __makeref(o);

一个重要的区别在于 TypedReference 是“通用的”;它可用于存储对任何类型变量的引用。访问这样的引用需要指定它的类型,例如__refvalue(tr, object),如果不匹配,则抛出异常。

要实现类型检查,TypedReference 必须有两个字段,一个是变量的实际地址,另一个是指向其类型表示的指针。恰好地址是第一个字段。

因此,首先使用__makeref 获取对变量o 的引用。强制转换 (IntPtr**)(&tr) 将结构视为 IntPtr*(指向通用指针类型的指针)的数组(通过指针表示),通过访问指向它的指针。指针首先被取消引用以获得第一个字段,然后那里的指针再次被取消引用以获得实际存储在变量 o 中的值——指向对象本身的指针。

不过,从2012年开始,我想出了一个更好更安全的解决方案:

public static class ReferenceHelpers
{
public static readonly Action<object, Action<IntPtr>> GetPinnedPtr;

static ReferenceHelpers()
{
var dyn = new DynamicMethod("GetPinnedPtr", typeof(void), new[] { typeof(object), typeof(Action<IntPtr>) }, typeof(ReferenceHelpers).Module);
var il = dyn.GetILGenerator();
il.DeclareLocal(typeof(object), true);
il.Emit(OpCodes.Ldarg_0);
il.Emit(OpCodes.Stloc_0);
il.Emit(OpCodes.Ldarg_1);
il.Emit(OpCodes.Ldloc_0);
il.Emit(OpCodes.Conv_I);
il.Emit(OpCodes.Call, typeof(Action<IntPtr>).GetMethod("Invoke"));
il.Emit(OpCodes.Ret);
GetPinnedPtr = (Action<object, Action<IntPtr>>)dyn.CreateDelegate(typeof(Action<object, Action<IntPtr>>));
}
}

这将创建一个动态方法,该方法首先固定对象(因此其存储不会在托管堆中移动),然后执行接收其地址的委托(delegate)。在委托(delegate)执行期间,对象仍然被固定,因此可以安全地通过指针进行操作:

object o = new object();
ReferenceHelpers.GetPinnedPtr(o, ptr => Console.WriteLine(Marshal.ReadIntPtr(ptr) == typeof(object).TypeHandle.Value)); //the first pointer in the managed object header in .NET points to its run-time type info

这是固定对象的最简单方法,因为 GCHandle 要求类型是 blittable 才能固定它。它的优点是不使用实现细节、未记录的关键字和内存黑客攻击。

关于c# - C#中对象的内存地址,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/4994277/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com