cho*_*ave 12 c# memory clr object-reference
我很想知道C#对象引用如何在运行时(在.NET CLR中)在内存中表示.想到的一些问题是:
对象引用占用多少内存?在类的范围和方法的范围中定义时它是否不同?根据此范围(堆栈与堆),它所在的位置是否不同?
对象引用中维护的实际数据是什么?它只是一个指向它引用的对象的内存地址还是更多的内存地址?这是否根据是否在类或方法的范围内定义而有所不同?
与上面相同的问题,但这次是在谈论对引用的引用时,例如在通过引用将对象引用传递给方法时.1和2的答案如何变化?
Ken*_*rey 14
如果您了解C/C++指针,则最容易理解这个答案.指针只是某些数据的内存地址.
对象引用应该是指针的大小,通常在32位CPU上为4个字节,在64位CPU上为8个字节.无论定义在何处,它都是相同的.它存在的地方取决于它的定义.如果它是类的字段,它将驻留在它所属的对象的堆上.如果它是静态字段,则它位于堆的特殊部分中,不受垃圾回收的影响.如果它是局部变量,它将存在于堆栈中.
对象引用只是一个指针,可以将其可视化为包含内存中对象地址的int或long.无论定义在何处,它都是相同的.
这是作为指针的指针实现的.数据是相同的 - 只是一个内存地址.但是,给定的内存地址没有对象.相反,还有另一个内存地址,它是对象的原始引用.这是允许修改参考参数的原因.通常,当方法完成时,参数会消失.由于对对象的引用不是参数,因此将保留对此引用的更改.对引用的引用将消失,但不会引用.这是传递参考参数的目的.
您应该知道的一件事是,值类型存储在适当的位置(没有内存地址,而是直接存储在内存地址的位置 - 参见#1).将它们传递给方法时,会生成一个副本,并在该方法中使用该副本.当它们通过引用传递时,传递一个内存地址,它将值类型定位在内存中,允许它被更改.
编辑:正如dlev指出的那样,这些答案并不是硬性规定,因为没有规则说明这是必须的..NET可以随意实现这些问题.这是实现它的最可能方式,因为这是英特尔CPU内部工作的方式,因此使用任何其他方法可能效率低下.
希望我没有太多困惑你,但随意问你是否需要澄清.
Jos*_*eld 14
.NET堆和堆栈 这是对堆栈和堆如何工作的彻底处理.
C#和许多其他使用堆的OOP语言在一般的参考语言中使用Handles而不是Pointers作为此上下文中的引用(C#也能够使用指针!)指针类比适用于一些一般概念,但这个概念模型分解为类似的问题这个.请参阅Eric Lippert关于此主题的优秀帖子Handles is Not Addresses
Handle是指针的大小是不合适的.(虽然它可能巧合地相同)Handles是对象的别名,并不要求它们是对象的正式地址.
在这种情况下,CLR碰巧使用句柄的实际地址:从上面的链接:
... CLR实际上实现了托管对象引用作为垃圾收集器拥有的对象的地址,但这是一个实现细节.
所以是的,32位架构上的句柄可能是4个字节,64字节架构上的8个字节,但这不是"肯定",并且它不是直接因为指针.值得注意的是,取决于编译器实现和使用的地址范围,某些类型的指针可以在大小上不同.
在所有这些上下文中,您可以通过指针类比来对此进行建模,但重要的是要实现Handles不需要是地址.如果将来想要CLR可以选择改变它,并且CLR的消费者不应该知道更好.
这个微妙点的最终驱动力:
这是一个C#指针:
int* myVariable;
Run Code Online (Sandbox Code Playgroud)
这是一个C#句柄:
object myVariable;
Run Code Online (Sandbox Code Playgroud)
他们不一样.
你可以做一些像指针上的数学,你不应该使用Handles.如果您的句柄恰好像指针一样实现,并且您使用它就像它是一个指针一样,您在某些方面滥用句柄可能会让您以后遇到麻烦.
| 归档时间: |
|
| 查看次数: |
4671 次 |
| 最近记录: |