【问题标题】:How are objects stored in memory?对象如何存储在内存中?
【发布时间】:2017-02-18 14:59:39
【问题描述】:

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

给定以下person 类:

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

    public int age { get; set; }
}

我相信Person 类型的初始变量在内存中将具有以下结构:

问题:

  • 首先,我的理解是否存在重大/明显缺陷? (我几乎可以肯定存在,因为以我描述的方式处理对象似乎效率低下;尤其是name 指针指向字符串成员的 char 集合的方式)

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

  • 和上面的问题类似,但是对于引用类型的成员,对象是否持有指向指针的指针? (即在我的图中引用 char 集合的名称指针)

  • 最后,如果我的Person 类的成员是字段而不是属性,会有什么不同吗?

更新:根据 Sweeper 和 Tim 的回答更新了图表,我认为现在是正确的。

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

【问题讨论】:

    标签: c# .net memory-management


    【解决方案1】:

    有一些错误。你弄错了int 成员,它是一个值类型。所以没有指针,它包含在 Person 对象的存储中,占用 4 个字节。 name 对象引用看起来也不太正确,它指向一个 String 对象。字符串中的字符包含在字符串的存储空间中,就像int 一样。或者换一种说法,String 对象存储的大小是可变的,只要存储字符所需的大​​小就可以了。

    所以访问 Person 对象的成员只需要解引用两个指针,这样效率更高。

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

    属性在运行时不存在,它是编译器提供的抽象。大多数情况下,编译器会为其分配一个字段,除非您自己提供 getter 和 setter 方法。所以绘图中的“姓名”和“年龄”实际上是字段,它们会有不同的名称。

    【讨论】:

      【解决方案2】:

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

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

      对于引用类型成员,它持有一个引用,这在概念上与指针的概念相同,占用 64 位空间(或 32 位,取决于架构),但正如我上面提到的那样有些不同。

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

      【讨论】:

        【解决方案3】:

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

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

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

        我的理解有什么重大/明显的缺陷吗?

        是的。我会在回答以下问题时提及它们。

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

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

        但是对于引用类型成员,对象是否持有指向指针的指针? (即在我的图中引用 char 集合的名称指针)

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

        【讨论】:

        • 感谢您的解释。我已经根据您和 Tim 的回答添加了一个更新的图表,我认为现在是正确的?
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2015-03-24
        • 2010-09-29
        • 2012-12-14
        • 2012-08-25
        • 2021-12-04
        • 1970-01-01
        相关资源
        最近更新 更多