简体   繁体   English

Memory分配:栈还是堆?

[英]Memory allocation: Stack vs Heap?

I am getting confused with memory allocation basics between Stack vs Heap .我对Stack 与 Heap之间的 memory 分配基础感到困惑。 As per the standard definition (things which everybody says), all Value Types will get allocated onto a Stack and Reference Types will go into the Heap .根据标准定义(每个人都这么说),所有值类型都将分配到Stack中,而引用类型将 go 分配到Heap中。

Now consider the following example:现在考虑以下示例:

class MyClass
{
    int myInt = 0;    
    string myString = "Something";
}

class Program
{
    static void Main(string[] args)
    {
       MyClass m = new MyClass();
    }
}

Now, how does the memory allocation will happen in c#?现在,memory 分配将如何发生在 c# 中? Will the object of MyClass (that is, m ) will be completely allocated to the Heap? MyClass的object(也就是m )会不会被完全分配到Heap? That is, int myInt and string myString both will go to heap?也就是说, int myIntstring myString都会将 go 放到堆中?

Or, the object will be divided into two parts and will be allocated to both of the memory locations that is, Stack and Heap?或者,object会被分成两部分,分别分配给memory两个位置,即Stack和Heap?

You should consider the question of where objects get allocated as an implementation detail.您应该考虑将对象分配到何处的问题作为实现细节。 It does not matter to you exactly where the bits of an object are stored.对象的位存储在哪里对您来说并不重要。 It may matter whether an object is a reference type or a value type, but you don't have to worry about where it will be stored until you start having to optimize garbage collection behavior.对象是引用类型还是值类型可能很重要,但在开始优化垃圾收集行为之前,您不必担心它将存储在哪里。

While reference types are always allocated on the heap in current implementations, value types may be allocated on the stack -- but aren't necessarily.虽然在当前实现中引用类型总是在堆上分配,但值类型可以在堆栈上分配——但不一定。 A value type is only allocated on the stack when it is an unboxed non-escaping local or temporary variable that is not contained within a reference type and not allocated in a register.仅当值类型是未包含在引用类型中且未在寄存器中分配的未装箱的非转义本地或临时变量时,才在堆栈上分配值类型。

  • If a value type is part of a class (as in your example), it will end up on the heap.如果值类型是类的一部分(如您的示例中),它将最终出现在堆上。
  • If it's boxed, it will end up on the heap.如果它被装箱,它将最终在堆上。
  • If it's in an array, it will end up on the heap.如果它在一个数组中,它将最终在堆上。
  • If it's a static variable, it will end up on the heap.如果它是一个静态变量,它将最终在堆上。
  • If it's captured by a closure, it will end up on the heap.如果它被闭包捕获,它将最终在堆上。
  • If it's used in an iterator or async block, it will end up on the heap.如果它在迭代器或异步块中使用,它将最终在堆上。
  • If it's created by unsafe or unmanaged code, it could be allocated in any type of data structure (not necessarily a stack or a heap).如果它是由不安全或非托管代码创建的,它可以分配在任何类型的数据结构中(不一定是堆栈或堆)。

Is there anything I missed?有什么我错过的吗?

Of course, I would be remiss if I didn't link to Eric Lippert's posts on the topic:当然,如果我没有链接到 Eric Lippert 关于该主题的帖子,我将是失职:

m is allocated on the heap, and that includes myInt . m在堆上分配,其中包括myInt The situations where primitive types (and structs) are allocated on the stack is during method invocation, which allocates room for local variables on the stack (because it's faster).在堆栈上分配原始类型(和结构)的情况是在方法调用期间,它为堆栈上的局部变量分配空间(因为它更快)。 For example:例如:

class MyClass
{
    int myInt = 0;

    string myString = "Something";

    void Foo(int x, int y) {
       int rv = x + y + myInt;
       myInt = 2^rv;
    }
}

rv , x , y will all be on the stack. rvxy都将在堆栈上。 myInt is somewhere on the heap (and must be access via the this pointer). myInt在堆上的某个地方(并且必须通过this指针访问)。

"All VALUE Types will get allocated to Stack" is very, very wrong; “所有 VALUE 类型都将分配给堆栈”是非常非常错误的; struct variables can live on the stack, as method variables.结构变量可以作为方法变量存在于堆栈中。 However, fields on a type live with that type .但是,类型上的字段与该类型一起存在 If a field's declaring type is a class, the values are on the heap as part of that object.如果字段的声明类型是类,则值作为该对象的一部分在堆上。 If a field's declaring type is a struct, the fields are part of that struct where-ever that struct lives.如果一个字段的声明类型是一个结构,那么无论该结构在哪里,这些字段都是该结构的一部分。

Even method variables can be on the heap, if they are captured (lambda/anon-method), or part of (for example) an iterator block.甚至方法变量可以在堆上,如果它们被捕获(lambda/anon-method),或者是(例如)迭代器块的一部分。

Stack

The stack is a block of memory for storing local variables and parameters . stack是一块内存,用于存储local variablesparameters The stack logically grows and shrinks as a function is entered and exited.随着函数的进入和退出,堆栈在逻辑上会增长和缩小。

Consider the following method:考虑以下方法:

public static int Factorial (int x)
{
    if (x == 0) 
    {
        return 1;
    }

    return x * Factorial (x - 1);
}

This method is recursive, meaning that it calls itself.此方法是递归的,这意味着它会调用自身。 Each time the method is entered, a new int is allocated on the stack , and each time the method exits, the int is deallocated .每次进入方法时,都会在堆栈上分配一个新的 int每次方法退出时,都会释放 int


Heap

  • The heap is a block of memory in which objects (ie, reference-type instances ) reside.堆是objects (即reference-type instances )驻留的一块内存。 Whenever a new object is created, it is allocated on the heap, and a reference to that object is returned.每当创建一个新对象时,它都会在堆上分配,并返回对该对象的引用。 During a program's execution, the heap starts filling up as new objects are created.在程序执行期间,随着新对象的创建,堆开始填满。 The runtime has a garbage collector that periodically deallocates objects from the heap, so your program does not run Out Of Memory .运行时有一个垃圾收集器,它会定期从堆中释放对象,因此您的程序不会运行Out Of Memory An object is eligible for deallocation as soon as it's not referenced by anything that's itself alive .只要一个对象没有被任何本身alive东西引用,它就有资格被释放。
  • The heap also stores static fields .堆还存储static fields Unlike objects allocated on the heap (which can get garbage-collected), these live until the application domain is torn down .与在堆上分配的对象(可以被垃圾回收)不同, these live until the application domain is torn downthese live until the application domain is torn down

Consider the following method:考虑以下方法:

using System;
using System.Text;

class Test
{
    public static void Main()
    {
        StringBuilder ref1 = new StringBuilder ("object1");
        Console.WriteLine (ref1);
        // The StringBuilder referenced by ref1 is now eligible for GC.

        StringBuilder ref2 = new StringBuilder ("object2");
        StringBuilder ref3 = ref2;
        // The StringBuilder referenced by ref2 is NOT yet eligible for GC.
        Console.WriteLine (ref3); // object2
    }
}    

In the above example, we start by creating a StringBuilder object referenced by the variable ref1, and then write out its content.在上面的例子中,我们首先创建了一个由变量 ref1 引用的 StringBuilder 对象,然后写出它的内容。 That StringBuilder object is then immediately eligible for garbage collection, because nothing subsequently uses it.然后该 StringBuilder 对象立即有资格进行垃圾收集,因为随后没有人使用它。 Then, we create another StringBuilder referenced by variable ref2, and copy that reference to ref3.然后,我们创建另一个由变量 ref2 引用的 StringBuilder,并将该引用复制到 ref3。 Even though ref2 is not used after that point, ref3 keeps the same StringBuilder object alive—ensuring that it doesn't become eligible for collection until we've finished using ref3.即使 ref2 在那之后不再使用,ref3 也会保持同一个 StringBuilder 对象处于活动状态——确保在我们使用完 ref3 之前它没有资格被收集。

Value-type instances (and object references) live wherever the variable was declared.值类型实例(和对象引用)存在于声明变量的任何地方。 If the instance was declared as a field within a class type, or as an array element, that instance lives on the heap.如果实例被声明为类类型中的字段或数组元素,则该实例位于堆上。

Each time an object is created in it goes into the area of memory known as heap.每次在其中创建对象时,它都会进入称为堆的内存区域。 The primitive variables like int and double are allocated in the stack, if they are local method variables and in the heap if they are member variables .像 int 和 double 这样的原始变量如果是局部方法变量,则分配在堆栈中;如果它们是成员变量,则分配在堆中。 In methods local variables are pushed into stack when a method is invoked and stack pointer is decremented when a method call is completed.在方法中,局部变量在调用方法时被压入堆栈,而在方法调用完成时堆栈指针递减。 In a multithreaded application each thread will have its own stack but will share the same heap.在多线程应用程序中,每个线程都有自己的堆栈,但将共享同一个堆。 This is why care should be taken in your code to avoid any concurrent access issues in the heap space.这就是为什么在你的代码中应该小心避免堆空间中的任何并发访问问题。 The stack is threadsafe (each thread will have its own stack) but the heap is not thread safe unless guarded with synchronisation through your code.堆栈是线程安全的(每个线程都有自己的堆栈),但堆不是线程安全的,除非通过代码同步保护。

This link is also useful http://www.programmerinterview.com/index.php/data-structures/difference-between-stack-and-heap/这个链接也很有用http://www.programmerinterview.com/index.php/data-structures/difference-between-stack-and-heap/

simple measures简单的措施

Value type can be stred on THE STACK ,it is the implementaional detail it can be allocated to the some futuristist data structure.值类型可以字符串在堆栈上,它是可以分配给一些未来主义数据结构的实现细节。

so, it is better to understand how value and reference type works , Value type will be copied by value that means when you pass a value type as a param to a FUNCTION than it will be copied by nature means you will have a total new copy.因此,最好了解值和引用类型的工作原理,值类型将按值复制,这​​意味着当您将值类型作为参数传递给 FUNCTION 时,它会被自然复制,这意味着您将拥有一个全新的副本.

Reference types are passed by reference ( againg do not consider reference will store a address again in some future versions ,it may be stored on some other data structures.)引用类型是通过引用传递的(在未来的某些版本中,再次考虑到引用会再次存储地址,它可能会存储在其他一些数据结构中。)

so in your case所以在你的情况下

myInt is a int which is ecapsulated in a class which offcourse an reference type so it will be tied to the instance of the class which will be stored on 'THE HEAP'. myInt 是一个 int,它被封装在一个与引用类型无关的类中,因此它将与将存储在“堆”上的类的实例相关联。

i would suggest , you can start reading blogs written by ERIC LIPPERTS.我建议,你可以开始阅读 ERIC LIPPERTS 写的博客。

Eric's Blog 埃里克的博客

m is a reference to an object of MyClass so m is stores in the stack of main thread but the object of MyClass stores in the heap. m 是对 MyClass 对象的引用,因此 m 存储在主线程的堆栈中,但 MyClass 的对象存储在堆中。 Therefore myInt and myString store in the heap.因此 myInt 和 myString 存储在堆中。 Note that m is only a reference (an address to memory) and is on main stack.请注意, m 只是一个引用(内存地址)并且位于主堆栈上。 when m deallocated then GC clear the MyClass object from the heap For more detail read all four parts of this article https://www.c-sharpcorner.com/article/C-Sharp-heaping-vs-stacking-in-net-part-i/当 m 被释放时,GC 从堆中清除 MyClass 对象有关更多详细信息,请阅读本文的所有四个部分https://www.c-sharpcorner.com/article/C-Sharp-heaping-vs-stacking-in-net-第一部分/

As per the standard definition (things which everybody says), all Value Types will get allocated onto a Stack and Reference Types will go into the Heap.根据标准定义(每个人都说),所有值类型都将分配到堆栈中,引用类型将进入堆中。

This is wrong.这是错误的。 Only local (in the context of a function) value types/arrays of value types are allocated on the stack.只有本地(在函数的上下文中)值类型/值类型数组在堆栈上分配。 Everything else is allocated on the heap.其他所有内容都分配在堆上。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM