2012-09-28 21 views
1

因此,我已经多次看到了有关在C#中获取引用对象的物理地址的问题,并且普遍认为这是不可能的因为你不能通过GCHandleType.Pinned调用GCHandle.Alloc这将允许你获取固定对象的地址。引用对象的地址在即时窗口中工作,但不在编译代码中

我发现奇怪的是,在Visual Studio调试器中,我可以将对象从本地窗口拖到内存调试窗口,并查看地址和内存以查找引用对象。我甚至可以输入即时窗口&obj并获取对象的实际地址(该地址正确对应于存储器窗口中显示的地址)。

但是它为什么我不能让我的编译代码相同的呼叫...即:

object someObject = new Object(); 
&obj; // Compiler Error: Cannot take the address of, get the size of, or declare a pointer to a managed type ('object') 

立即\ Memory窗口是如何允许获得托管类型,甚至显示的地址内存的布局,但C#不能做到这一点?有没有什么办法可以得到C#中引用对象的实际地址?

回答

2

调试器比你自己的代码有很大的优势。它可以在运行时以没有代码的形式查看进程状态。因此,获取对象的地址不是问题,垃圾收集器不会运行以使其无效。

+0

但即时窗口如何执行无效的C#代码? –

+0

立即窗口中没有嵌入C#编译器。它只是评估表达式。它对&运算符没有任何问题。 –

0

Carbage Collector处理对象的生命周期。它在内存中也大致分为3个部分,分别称为gen0,gen1,gen2(Generations)。

在gen0中,快速生存对象驻留在分配的内存很小的地方。垃圾收集经常运行,因为那里有很多短暂的对象。如果一个对象获得gen0,它将被移到下一个gen。

当一个对象被垃圾回收时,所有其他对象都被重新排列在内存中,以保持可用内存空间可用。

但是在gen2中,最大和最长寿命的物体存在,内存很少被重新安排,因为它在gen2中移动对象花费太多。

所有这些内存引用和垃圾回收都是在C#这样的托管环境中为您提供'免费'的。

此外,有时会进行优化,例如:“字符串实习”。

+0

对不起,但我不明白这是如何解决这个问题的。 –

+0

我在说什么:因为GC已经重新排列了对象,内存引用'Now'在'将来'中可能不正确。 – Johnny

+1

@BrianRasmussen:当GC运行时,一个对象可以在堆内移动,其物理地址也会改变!这就解释了为什么你不能获得被管理对象的物理地址。这在即时窗口中没有问题,因为它只显示实际状态的快照。 –

相关问题