【问题标题】:Memory allocation on object creation对象创建时的内存分配
【发布时间】:2023-03-18 02:31:01
【问题描述】:

当我们实例化类/结构 Student 时,它将在堆栈和堆中分配多少内存?

我猜 id = 4 字节引用(32 位机器)和 name = 4 字节引用和facultyAdvisor = 4 字节引用。所以堆栈中总共有 12 个字节,实际大小将在堆中。此堆大小可能会有所不同,具体取决于我们分配给使用对象 obj(Student obj = new Student()) 的字段(id、name、facultyAdvisor)的值

struct 也一样吧?

public class Student { int id; string name; Professor facultyAdvisor; }

public struct Student { int id; string name; Professor facultyAdvisor; }

【问题讨论】:

    标签: c#


    【解决方案1】:

    首先注意stack and the heap are implementation details... as 是对象的大小。但是在当前的实现中,Student 中的 fields 的所有数据(当它是一个类时)都在堆上。存在对象开销以及字段占用的内存,但所有这些都将在堆上。

    如果您保留对新实例的 reference,并且将其保留在未捕获的局部变量中,而不是在迭代器块或异步方法中,则该引用将在堆栈中 (在当前实现中),因此在 32 位 CLR 上它将是 4 个字节。

    Student 是一个结构时,情况会有所改变:

    • 数据的位置(堆栈或堆)取决于值的使用方式 - 例如,如果它存储在类的实例变量中,它将与其余数据一起位于堆上;如果它在局部变量中(同样,未捕获且不在迭代器块或异步方法中),那么它将在堆栈中
    • 你没有创建一个单独的对象,只是一个,所以没有额外的开销——它真的只需要12个字节(假设Professor是一个引用类型)

    我有几篇您可能会觉得有用的文章/帖子:

    编辑:解决 Professor 问题,假设 Professor 是一个类 - 除非显式创建 Professor 对象,否则 Student 中的引用将简单地为空。创建一个新的Student不会自动创建一个新的Professor,只是因为有一个该类型的字段。对Professor 的引用只是Student 数据的一部分——它存在于id 所在的任何地方——所以如果Student 是一个类,那么引用只存在于堆上,如果Student是一个结构,那么它取决于Student 值的创建位置,如上所示。

    【讨论】:

    • 编辑了问题。请回答
    • @Alavudeen:完成,虽然我不太确定我是否理解编辑后的问题。如果我的编辑不让您满意,请澄清问题。
    • 我已澄清您对我编辑的问题的回答。但仍然无法得出结论
    • @Alavudeen:是的,恐怕是这样。你的问题在英语方面并没有真正的意义——我很欣赏它可能不是你的第一语言,但它确实让人很难回答:(你读过我链接的文章吗?他们在很多方面都涵盖了所有这些详细信息。如果您已彻底阅读这些内容但仍有疑问,请发布一段更具体的代码(最好是完整的程序)以及有关它的非常具体的问题。
    【解决方案2】:

    假设 32 位 CLR(在 64 位 CLR 上引用将是 64 位)并且只考虑学生的堆分配

    班级学生{}班级教授{}

    • 堆栈:4 个字节
    • 堆:4字节(int)+ 4字节(教授参考)+ 4字节(字符串参考)+ 12字节(对象头)= 24字节

    class Student{} struct Professor{}

    • 堆栈:4 个字节
    • 堆:4 字节 (int) + 处理器大小 + 4 字节(字符串引用)+ 12 字节(对象头)= ??字节

    struct Student{} class Professor{}

    • 堆栈:4 字节(int)+ 4 字节(字符串引用)+ 4 字节(教授引用)= 12 字节
    • 堆:0 字节

    struct Student{} struct Professor{}

    • 堆栈:4 字节(int)+ 4 字节(字符串引用)+ 教授的大小 = ??字节
    • 堆:0 字节

    【讨论】:

    • 谢谢乔恩 - 由于某种原因我错过了名字在那里 - 编辑
    • class Student{} class Professor{} Stack: 4 bytes Heap: 4 bytes (int) + 4 bytes (Professor Reference) + 4 bytes (string reference) + 12 bytes (object header) = 24字节。在这种情况下,堆中有 4 个字节(教授参考)?如果是这样,实际对象住在哪里?此外,正如您所说的堆栈中有 4 个字节,这 4 个字节的堆栈引用是否会指向所有字段(id、name 和facultyAdvisor)。有可能吗?
    • 堆栈上的 4 个字节是学生引用,它指向堆上的学生对象(及其所有字段),教授引用与学生一起分配,但教授对象是堆上的单独分配
    • 嗨,由于教授对象是堆上的一个单独分配,它的引用应该存储在堆栈上吧?它如何与堆中的学生对象一起使用。
    • 否 - 对教授的引用是学生状态的一部分,因此与学生对象一起存储在堆中
    【解决方案3】:

    您可以使用GC.GetTotalMemory(true) 调用来测量实例化前后的内存消耗以测量堆分配

    【讨论】:

      猜你喜欢
      • 2012-02-21
      • 2014-03-31
      • 1970-01-01
      • 2012-01-08
      • 1970-01-01
      • 1970-01-01
      • 2015-10-15
      • 2013-01-21
      • 2014-03-17
      相关资源
      最近更新 更多