内存分配:堆栈还是堆?

我对堆栈与堆之间的内存分配基础感到困惑。 根据标准定义(每个人都说),所有的值types将被分配到一个堆栈,并且引用types将被放入堆中

现在考虑下面的例子:

class MyClass { int myInt = 0; string myString = "Something"; } class Program { static void Main(string[] args) { MyClass m = new MyClass(); } } 

现在,如何在C#中发生内存分配? MyClass的对象(即m )是否会被完全分配给堆? 那是int myIntstring myString都会去堆?

或者,该对象将被分成两部分,并且将被分配到两个存储位置,堆栈和堆?

m被分配在堆上,包括myInt 。 原始types(和结构)分配在堆栈上的情况是在方法调用期间,这为堆栈中的局部variables分配空间(因为速度更快)。 例如:

 class MyClass { int myInt = 0; string myString = "Something"; void Foo(int x, int y) { int rv = x + y + myInt; myInt = 2^rv; } } 

rvxy都会在堆栈中。 myInt是在堆的某个地方(并且必须通过this指针访问)。

您应该考虑将对象分配的位置作为实现细节。 对于存储对象的位的确切位置无关紧要。 可能很重要的一个对象是引用types还是值types,但是您不必担心它将被存储在何处,直到您开始优化垃圾回收行为。

虽然引用types总是在当前实现的堆中分配,但是值types可以分配在堆栈上 – 但不一定。 值types仅在堆栈上分配时,它是一个未装箱的非转义本地或临时variables,它不包含在引用types中,也未分配到寄存器中。

  • 如果一个值types是一个类的一部分(如你的例子),它将在堆上结束。
  • 如果它被装箱,它将会堆积起来。
  • 如果它在一个数组中,它将在堆上结束。
  • 如果它是一个静态variables,它将在堆上结束。
  • 如果它被closures捕获,它将最终堆在堆上。
  • 如果它在迭代器或asynchronous块中使用,它将在堆上结束。
  • 如果它是由不安全的或非托pipe的代码创build的,它可以分配在任何types的数据结构中(不一定是堆栈或堆)。

有什么我错过了吗?

当然,如果我没有链接到Eric Lippert关于这个主题的post,

  • 堆栈是一个实现细节,第一部分
  • 该堆栈是一个实现细节,第二部分
  • 也许是最好的: 关于价值types的真理

“所有VALUEtypes将被分配到堆栈”是非常非常错误的; 结构variables可以作为方法variables存在于堆栈中。 然而,一个types的字段与这种types生活在一起 。 如果某个字段的声明types是一个类,则这些值作为该对象的一部分存放在堆上。 如果一个字段的声明types是一个结构体,那么这个结构体就是那个结构体所在的结构体的一部分。

即使方法variables可以在堆上,如果它们被捕获 (lambda / anon-method),或者(例如)迭代器块的一部分。

优秀的解释:

  • 第1部分: http : //www.c-sharpcorner.com/uploadfile/rmcochran/csharp_memory01122006130034pm/csharp_memory.aspx

  • 第2部分: http : //www.c-sharpcorner.com/UploadFile/rmcochran/csharp_memory2B01142006125918PM/csharp_memory2B.aspx

  • 第3部分: http : //www.c-sharpcorner.com/UploadFile/rmcochran/chsarp_memory401152006094206AM/chsarp_memory4.aspx

  • 第4部分: http : //www.c-sharpcorner.com/uploadfile/rmcochran/csharp_memory_401282006141834pm/csharp_memory_4.aspx

简单的措施

值types可以在STACK上进行定义,它是可以分配给某些未来主义数据结构的实现细节。

因此,最好理解值和引用types是如何工作的,值types将被值复制,这​​意味着当您将一个值types作为parameter passing给函数时,它将被自然复制,意味着您将拥有全新的副本。

引用types是通过引用传递的(againg不考虑引用将在未来版本中再次存储地址,它可能存储在其他一些数据结构中)。

所以在你的情况

myInt是一个inttypes,它封装在一个引用types的类中,因此它将被绑定到将存储在“HEAP”上的类的实例。

我build议,你可以开始阅读由ERIC LIPPERTS写的博客。

埃里克的博客

每次创build对象时,都会进入称为堆的内存区域。 像int和double这样的基本variables在堆栈中分配,如果它们是本地方法variables,则在堆中分配,如果它们是成员variables的话。 在方法中,当方法被调用时,局部variables被压入堆栈,并且在方法调用完成时,堆栈指针被减less。 在multithreading应用程序中,每个线程都有自己的堆栈,但是会共享相同的堆。 这就是为什么要在代码中注意避免堆空间中的任何并发访问问题。 堆栈是线程安全的(每个线程都有自己的堆栈),但堆不是线程安全的,除非通过代码保护同步。

这个链接也是有用的http://www.programmerinterview.com/index.php/data-structures/difference-between-stack-and-heap/