对象如何存储在内存中?

时间:2017-02-18 14:59:39

标签: c# .net memory-management

我试图了解如何使用.NET Framework将对象存储在内存中。

给出以下person类:

public class Person
{
    public string name { get; set; }

    public int age { get; set; }
}

我相信Person类型的已启动变量在内存中具有以下结构: Person Memory Structure

问题:

  • 首先,他的理解中存在哪些重大/明显的缺陷? (我几乎可以肯定,因为它似乎无法按照我描述的方式处理对象;特别是name指针指向字符串成员的char集合的方式)

  • 其次,对于类(IE Age)的值类型成员,它们是存储在对象本身内(因此在与对象相同的内存地址中),还是它们被分配了自己的地址,然后对象指向它? (如我的图表所示)

  • 与上述问题类似,但对于引用类型成员,对象是否包含指向指针的指针? (I.E我的图表中引用char集合的名称指针)

  • 最后,如果Person类的成员是字段而不是属性,会不会有所作为?

更新:根据Sweeper&的答案更新了图表。蒂姆,我认为现在是正确的。

Correct Diagram

注意:指针已更改为引用,因为这是托管代码。

3 个答案:

答案 0 :(得分:3)

有一些错误。你的int成员错了,它是一个值类型。所以没有指针,它包含在Person对象的存储中并占用4个字节。 name 对象引用也看起来不正确,它指向一个String对象。字符串中的字符包含在字符串的存储中,与int非常相似。换句话说,String对象存储的大小是可变的,与存储字符所需的大​​小一样大。

因此,访问Person对象的成员只需要解除引用两个指针,效率更高。

是的,Person类型的变量只存储指针。 GC压缩堆时会更新它。

属性在运行时不存在,它是编译器提供的抽象。最常见的是编译器将为其分配一个字段,除非您自己提供getter和setter方法。所以"名称"和"年龄"在你的绘图中实际上是字段,它们会有不同的名称。

答案 1 :(得分:2)

在.net世界中,指针指向非托管内存,对象引用引用托管对象。垃圾收集器可以随时移动对象,因此指向它们的指针将在没有警告的情况下被销毁。这个概念是一样的,但是有区别,因为你确实可以在不安全的C#代码中有指针。如果抓取指向对象的指针,并且该对象移动,则指针指向任意内存空间。但是,会保留对象引用。

关于年龄的问题。它存储在对象本身中,在结构中占据32位 - 而不是指向int32的引用/指针

对于引用类型成员,它拥有一个引用,它在概念上与指针的想法相同,占用64位空间(或32位,具体取决于体系结构),但有些不同,如上所述。

最后,匿名属性实际上是创建隐藏字段和自动编写代码来设置和重新调整这些字段。存储是相同的,但通过属性而不是直接访问字段的成本非常低。

答案 2 :(得分:1)

我将从最容易回答的问题开始:

  

如果我的Person类的成员是字段而不是属性,它会有所不同吗?

没有。代码中的属性只是语法糖。编译代码时,{ get; set; }的这些属性将变为带有getter和setter的字段。

  

我的理解中是否有任何重大/明显的缺陷?

是。当我回答以下问题时,我会提及它们。

  

其次,对于类(IE Age)的值类型成员,它们是否存储在对象本身内(因此在与对象相同的内存地址中),或者它们是否被分配了自己的地址,然后对象指向对吗? (如我的图表所示)

你的第一个陈述是正确的。值类型存储在对象中。 Person对象中没有指向int的指针。换句话说,你的图表是错误的。

  

但是对于引用类型成员,对象是否包含指向指针的指针? (I.E在我的图表中引用char集合的名称指针)

在这种情况下,char[]是您注意到的引用类型。但它实际上拥有一堆char s,它们是值类型。所以不,字符存储在char数组中,就像Age存储在Person中一样。另一方面,如果这是string[],则会有一个指向数组的指针,该指针将包含指向字符串对象的指针。这也意味着你的图表是错误的。