【问题标题】:Static class memory allocation where it is stored C#存储它的静态类内存分配 C#
【发布时间】:2016-02-07 07:53:43
【问题描述】:

我读了一篇让我对内存分配感到困惑的文章,其中指出:

单例对象存储在堆上,而静态类则存储在堆上。 存储在堆栈中。

链接是:http://www.dotnetjalps.com/2013/06/Static-vs-Singleton-in-Csharp-Difference-between-Singleton-and-Static.html

但是在一些 Stackoverflow 问题中,比如

How is memory allocated for a static variable?

是这样描述的

静态变量存储在堆上,无论它们被声明为引用类型还是值类型。只有一个 无论创建多少个实例,总槽位。

所以我对静态类的堆栈或堆存储感到困惑。如何为静态类分配内存,为什么?单例类的内存是如何分配的?

【问题讨论】:

  • 类不会占用内存,但对象会。存储在堆栈中的语句静态类对我来说听起来很荒谬。
  • @sriram 是的。静态变量呢?
  • @SivaRajini 静态变量存储在堆的某处。
  • 如果你使用一个类的实例,它将存储在堆中,但堆中有一些区域用于静态和非静态变量。

标签: c# memory-management


【解决方案1】:

实例是通过 new 关键字创建的,并驻留在堆中,如果没有人指向它,将被垃圾收集。但是在静态类静态构造函数的情况下,只调用一个来初始化所有静态成员的内存,这些静态成员将驻留在堆栈以外的全局内存位置,并且静态成员保持活动状态,除非应用程序正在运行。它不会被垃圾收集。

【讨论】:

  • 使用new 关键字创建的实例没有什么特别之处。并且不能保证任何对象都会在堆上创建。我当然可以写int x = new int();
【解决方案2】:

.NET Framework 中有四种可能的根类型:

  • 堆栈引用:对本地对象的引用。这样的根在方法执行期间存在。
  • 静态引用:对静态对象的引用。这些根存在于整个应用域生命周期中。
  • 句柄:通常,这些是用于托管和非托管代码之间通信的引用。这样的根必须至少存在,直到非托管代码需要“托管”对象。
  • 终结器引用:对等待终结的对象的引用。这些根在运行终结器之前一直存在。

https://www.jetbrains.com/help/dotmemory/Analyzing_GC_Roots.html

高频堆

静态数据和 C# 程序中定义的常量存储在堆上。由于它们在应用程序的整个生命周期中都存在,因此不需要进行垃圾收集,因此存储在加载程序堆中,而不是普通的垃圾收集堆中。具体来说,静态数据存储在高频堆上——每个 AppDomain 都存在的加载器堆之一。

Static Data and Constants Are Stored on the Heap

【讨论】:

    【解决方案3】:

    静态变量进入Heap内部的特殊原因。它被称为高频堆,所有的静态变量都进入内存中的高频堆高频堆中的对象不是由 GC 收集的垃圾,因此静态变量在应用程序的整个生命周期内都可用。

    我们需要显式取消分配它,然后我们必须将它设置为 null 以便 GC 可以清除它分配的内存。

    【讨论】:

      【解决方案4】:

      Sriram Sakthivel 解释得很好。基本上堆内存分为两个主要部分。对象堆内存和Loader堆内存。据我了解,所有非静态引用类型都存储在对象堆中,所有静态对象(可能是引用类型或值类型)都存储在加载器堆中。 Gc 永远不会在加载程序堆上工作,这就是为什么它们只初始化一次并通过应用程序保留在内存中的原因。

      【讨论】:

        【解决方案5】:

        类不会占用内存,但对象会。 “静态类存储在堆栈中”这句话对我来说听起来很荒谬。

        类不存储在内存中。当一个类被加载时,它们的元数据可能会被加载到内存中并被缓存。除此之外,类不存储在内存中。

        问问自己,如果静态类存储在堆栈中,您如何能够在所有线程中访问它?

        静态变量

        静态变量是 MethodTable 的重要组成部分 数据结构。它们被分配为 MethodTable 权限的一部分 在方法表槽数组之后。所有原始静态类型都是 内联静态值对象,如结构和引用 类型通过句柄表中创建的 OBJECTREF 引用。 MethodTable 中的 OBJECTREF 引用 AppDomain 中的 OBJECTREF 句柄表,指的是堆创建的对象实例。一次 创建后,句柄表中的 OBJECTREF 将保留对象实例 在卸载 AppDomain 之前一直在堆上运行

        参考this article for more info

        请停止阅读该博文或该作者的任何博文。这太荒谬了。

        【讨论】:

        • 我认为,静态类有记忆。请阅读我的答案,如果我错了请纠正我
        • @SurenSrapyan 静态类不存储在任何地方。但是存储了静态字段。它存储在某个特殊位置的堆中。要知道那个特殊位置是什么,请阅读我的回答中的块引用部分
        猜你喜欢
        • 2015-10-22
        • 2015-07-23
        • 1970-01-01
        • 1970-01-01
        • 2013-01-13
        • 2012-01-13
        • 2011-07-18
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多