Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/.net/22.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 内存分配:堆栈还是堆?_C#_.net_Stack_Heap - Fatal编程技术网

C# 内存分配:堆栈还是堆?

C# 内存分配:堆栈还是堆?,c#,.net,stack,heap,C#,.net,Stack,Heap,我对堆栈与堆之间的内存分配基础感到困惑。根据标准定义(每个人都说的事情),所有值类型将分配到堆栈,引用类型将进入堆 现在考虑下面的例子: class MyClass { int myInt = 0; string myString = "Something"; } class Program { static void Main(string[] args) { MyClass m = new MyClass(); } } 现在,

我对堆栈与堆之间的内存分配基础感到困惑。根据标准定义(每个人都说的事情),所有值类型将分配到堆栈引用类型将进入

现在考虑下面的例子:

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

class Program
{
    static void Main(string[] args)
    {
       MyClass m = new MyClass();
    }
}
现在,在c#中内存分配将如何进行?
MyClass
(即
m
)的对象是否将完全分配给堆?也就是说,
intmyint
stringmystring
都将进入堆


或者,对象将分为两部分,并将分配给两个内存位置,即堆栈和堆?

m
在堆上分配,其中包括
myInt
。在堆栈上分配原语类型(和结构)的情况是在方法调用期间,方法调用为堆栈上的局部变量分配空间(因为这样更快)。例如:

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
都将在堆栈上<代码> MyTime/Cuff>是堆上的某个地方(必须通过<代码>这个指针)访问。

< P>您应该考虑对象被分配为实现细节的问题。对你来说,一个对象的比特存储在什么地方并不重要。对象是引用类型还是值类型可能很重要,但在开始优化垃圾收集行为之前,您不必担心它将存储在何处

虽然在当前的实现中引用类型总是在堆上分配,但值类型可以在堆栈上分配,但不一定。只有当值类型是未包含在引用类型中且未在寄存器中分配的未装箱非转义局部或临时变量时,才会在堆栈上分配该值类型

  • 如果值类型是类的一部分(如示例中所示),那么它将在堆中结束
  • 如果它被装箱了,它最终会被放在堆上
  • 如果它在一个数组中,它将在堆中结束
  • 如果它是一个静态变量,那么它将在堆中结束
  • 如果它被一个闭包捕获,那么它最终将被放在堆上
  • 如果在迭代器或异步块中使用它,它将在堆中结束
  • 如果它是由不安全或非托管代码创建的,则可以在任何类型的数据结构(不一定是堆栈或堆)中进行分配
有什么我错过的吗

当然,如果我没有链接到Eric Lippert关于这个主题的帖子,那我就是失职了:

  • 也许是最好的一个:
“所有值类型都将被分配到堆栈”是非常非常错误的;结构变量可以作为方法变量存在于堆栈上。但是,类型上的字段与该类型共存。如果字段的声明类型是类,则值作为该对象的一部分在堆上。如果字段的声明类型是一个结构,则字段是该结构的一部分,该结构存在于该结构中

即使是方法变量,如果它们被捕获(lambda/anon方法),或者是迭代器块的一部分(例如),也可能在堆上。

很好的解释:

  • 第1部分:

  • 第2部分:

  • 第3部分:

  • 第4部分:

简单测量

值类型可以分布在堆栈上,它是实现细节,可以分配给某些未来派的数据结构

所以,更好地理解值和引用类型是如何工作的,值类型将被值复制,这意味着当您将值类型作为参数传递给函数时,它将被复制,这意味着您将拥有一个全新的副本

引用类型通过引用传递(AgaIn不考虑引用将在将来的版本中再次存储地址,它可以存储在其他一些数据结构上)。 那么你的情况呢

myInt是一个int,它被封装在一个类中,这个类当然是一个引用类型,因此它将绑定到将存储在“HEAP”上的类的实例

我建议,你可以开始阅读埃里克·利珀斯写的博客


每次在内存中创建对象时,它都会进入称为堆的内存区域。基本变量如下 如果int和double是本地方法变量,则在堆栈中分配;如果int和double是成员变量,则在堆中分配 变量。在方法中,当调用方法时,局部变量被推入堆栈 当方法调用完成时,堆栈指针将递减。在多线程应用程序中,每个线程 将有自己的堆栈,但将共享同一堆。这就是为什么在代码中要小心避免任何错误 堆空间中的并发访问问题。堆栈是线程安全的(每个线程都有自己的堆栈),但是 堆不是线程安全的,除非通过代码进行同步保护

此链接也很有用

Stack
堆栈
是一块内存,用于存储
局部变量
参数
。堆栈在逻辑上随着函数的输入和退出而增长和收缩

考虑以下方法:

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

    return x * Factorial (x - 1);
}
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
    }
}    
这个方法是递归的,这意味着它调用自己每次输入该方法时,会在堆栈上分配一个新的int,每次退出该方法时,会取消分配int


  • 堆是
    对象
    (即
    引用类型实例
    )所在的内存块。每当创建一个新对象时,就会在堆上分配它,并返回对该对象的引用。在程序执行期间,当创建新对象时,堆开始填满。运行时有一个垃圾收集器,它定期从堆中释放对象,因此程序不会在内存不足的情况下运行。对象符合释放条件