对象创建时的内存分配

本文关键字:内存 分配 创建 对象 | 更新日期: 2023-09-27 18:03:13

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

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

对于struct也是一样的?

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

对象创建时的内存分配

首先注意堆栈和堆是实现细节…物体的大小也是如此。但是在当前的实现中,Student字段的所有数据当它是一个类时都在堆上。有对象开销和字段占用的内存,但所有这些都将在堆上。

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

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

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

我有一些你可能会觉得有用的文章/帖子:

  • 内存和对象开销(特别是字符串,但也有其他类型)
  • 什么去了哪里-堆栈和堆,再次记住这是一个实现细节

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

假设32位CLR(引用在64位CLR上为64位)并且只考虑Student的堆分配

类学生{}类教授{}

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

class Student{} struct Professor{}

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

struct Student{} class教授{}

  • 栈:4字节(整型)+ 4字节(字符串引用)+ 4字节(教授引用)= 12字节
  • Heap: 0 bytes

struct Student{} struct Professor{}

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

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