【问题标题】:Stack and Heap memory effects?堆栈和堆内存效应?
【发布时间】:2011-10-21 19:09:33
【问题描述】:

在以下代码中:

MyClass oMyClass1;
MyClass oMyClass2 = null;

我怀疑以上两行将如何影响内存(堆栈和堆)。

会在堆栈中创建引用吗?

【问题讨论】:

    标签: c# .net memory-management heap-memory stack-memory


    【解决方案1】:

    严格来说,这取决于代码在哪里。

    如果代码在常规函数/方法中,它只会影响堆栈。不会对堆产生影响,因为尚未构造 MyClass 对象。

    假设 MyClass 是一个类(即引用类型),每个声明都会在堆栈上保留足够的空间来保存对 MyClass 对象的引用。

    这两个声明略有不同 - 第一个尚未初始化,因此任何尝试在 oMyClass1 设置为某个值之前访问它都会导致编译器错误。第二个已初始化,因此您不会收到编译器错误[尽管如果您在将其设置为引用实际对象之前访问 oMyClass2 的方法或属性,则会收到运行时错误,例如with oMyClass2 = new MyClass();].

    如果代码在类声明中:

    class Fred {
        MyClass oMyClass1;
        MyClass oMyClass2 = null;
    }
    

    那么它只会在 Fred 构造函数期间执行。在调用构造函数之前,空间(对于 Fred 对象,包括两个 MyClass 引用的空间)已经在堆上分配。这两行代码实际上没有任何作用,因为空间已经被初始化为 null。

    如果是在结构体声明中,效果会类似,只是在堆栈(如果结构体是本地的)或全局变量内存上(如果结构体是静态的)。 [虽然,公平地说,我有点不确定静态在 C# 中的分配位置 - 我只是假设它以类似于 C++ 的方式完成]

    【讨论】:

    • 正如我在一个现已删除的答案中所说的那样,不是类成员的值类型的实例并不总是存储在堆栈中。如果它们被 lambda 表达式或迭代器块捕获,它们将被存储在堆中。
    • 只有在本地引用时才会在堆栈上分配引用。如果他们是类成员,他们将在堆上。
    • @Frédéric 值得详细说明的是,如果它们被 lambda 捕获,它们不再是“本地人”。它们将被转换为对闭包类(即包装对象)上的属性的引用。闭包位于堆上。
    • @chibacity,没错,“本地人”确实会被“提升”为会员。
    • @chibacity - 我认为您只是在重申我在答案中写的内容。如果答案实际上是错误的,如果您能解释一下如何(我可能会学到一些东西!),我将不胜感激。但是感谢 Frédéric 的评论——我也是这么想的——lambda 表达式、匿名代表、Linq 等. 就我而言,只是创建额外类的简写方式。
    【解决方案2】:

    我怀疑以上两行将如何影响内存(堆栈和堆)。

    信息不足,2种可能:

    1. 它们是局部变量。在这种情况下,这 2 行在堆栈上进行了 2 次相同的分配(引用,始终为 32/64 位)(无论何时执行该方法以及执行多长时间)。堆上没有分配。

    2. 它们是类或结构中的字段。在这种情况下,这 2 行每行都会在创建实例时分配实例中引用的大小。该实例可以分配在堆栈上(当它们是结构成员时)或堆上(类成员)。

    【讨论】:

    • +1 经过编辑以区分第 2 点中的结构和类。
    猜你喜欢
    • 2011-06-13
    • 1970-01-01
    • 2018-09-27
    • 2019-05-17
    • 2011-10-09
    • 2016-07-25
    • 1970-01-01
    • 1970-01-01
    • 2011-08-15
    相关资源
    最近更新 更多