c# - 所有静态成员存储在哪里?

标签 c# .net static heap-memory stack-memory

<分区>

我正在尝试学习 C# 如何管理内存。我被静态元素困住了,我阅读了很多关于这个主题的博客和文章,但我找不到一个非常满意的答案。

让我们定义一个代码块来帮助找到答案。

class myClass
{
    static string myStr = "String Data";
    static int myInt = 12;
}

在你们分享答案之前,让我分享一下我对这个主题的了解。请随意同意或不同意并帮助我找到正确答案。

  • 静态只为一生。
  • 静态引用类型 (myStr),将在整个生命周期内保留在堆中。
  • 静态值类型 (myInt),将在整个生命周期内进入堆栈。

让我感到困惑的是我在互联网上找到的关于这个主题的一些答案。

混淆号 1:

When your program starts, it loads all the related assemblies into an AppDomain. When the assembly is loaded, all static constructors are called, including static fields. They will live in the there, and the only way to unload them, is to unload the AppDomain.

在上面几行中,明确提到所有静态元素都存储在 AppDomain 上。那么为什么互联网上的每个人都说“静态”元素存储在堆/堆栈上?

混淆号 2:

Every static variable is stored on the heap, regardless of whether it's declared within a reference type or a value type.

如果每个静态变量都存储在堆上。那为什么有人说值类型静态变量存储在栈上呢?

请帮助连接我的点以了解 C# 中静态变量的内存管理。非常感谢您宝贵的时间:)

最佳答案

首先,请注意所有这些都是实现细节。运行时唯一保证的是:

  • 当你请求一个静态字段时,它就在那里
  • 在使用类型之前的某个时刻执行静态构造函数

差不多就这些了。其他一切都是实现细节——规范不关心堆栈、堆或其他任何东西。这取决于运行时的实现,如果需要,有效的运行时可以将所有内容放在堆栈或堆上。并且不要忘记寄存器。

现在,让我们看看您已经发现的一些误解:

  • 静态是终生的 - 是的。它没有说明它存储在何时何地 - 只是在您需要时可用。兼容的运行时可以自由使用它想要的任何内存,甚至永远不会将字段加载到内存中(例如,将它保存在图像中,无论如何它已经在内存中)
  • 静态将在整个生命周期内继续存在 - 很可能是的。但它不是规范的一部分,只要有适当的保证,兼容的运行时就可以将它存储在任何它想要的地方,或者根本不在任何地方。另外,不要忘记“for life time”意味着“至少在 AppDomain 的生命周期内”;它可能会或可能不会在卸载域时被释放。
  • 静态值类型将在整个生命周期内进入堆栈 - 很可能不会。同样,这是一个实现细节,但堆栈的语义与静态值的意义完全不同。下一点将为您提供更多理由:
  • 加载程序集时,将调用所有静态构造函数,包括静态字段。 - 没有。没有这样的要求,也没有这样的保证。如果你依赖这个,你的程序就会崩溃(我以前见过很多次)。同样,一个实现细节,但在当前的 MSCLR 实现中,静态变量倾向于在它们自己的堆中分配,并且在需要定义它们的类型之前的某个时间。如果在静态构造函数中抛出异常,您可以很容易地看到这一点 - 它会导致 TypeLoadException,最有可能在首先引用该类型的方法中(不用说,这会使调试静态变得棘手) .
  • 引用类型在堆上,值类型在堆栈上。 - 不。这混淆了机制和语义。两者之间的唯一区别是它们的语义——其他一切都取决于实现。如果运行时可以在堆栈上保留引用类型的引用语义,那是完全有效的。即使使用当前的 MSCLR 运行时,值类型也始终存储在堆中 - 例如,每当它们被装箱或引用类型的成员时。

有些人可能会感到困惑。有些人不理解契约(Contract)与实际实现之间的区别。有些人根本不知道他们在说什么。我希望有一种简单的方法可以知道哪个是哪个,但是没有。如果有疑问,您可以查看 C#/CLR 规范,但这只会告诉您契约,而不是实际情况。

托管内存的全部意义在于您不应该关心这些实现细节。当然,就像任何抽象一样,它会泄漏——通过所有不同的层和抽象,了解事情的真实情况是有意义的,包括 CPU 微指令、内存缓存等。但这不是什么值得依赖的 - 实现可以随时更改,而且过去有很多次。

关于c# - 所有静态成员存储在哪里?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/38612009/

相关文章:

c# - .net 配置文件 AppSettings : NameValueCollection vs. KeyValueConfigurationCollection

static - dose openshift Website Nameservers 是静态的或将被更改

java - Java中的静态字符串路径

c# - 删除时使用哪种 session 方法?

android - 从 Alertdialog 启动另一个 Activity

c# - 在循环内部/外部声明变量会改变性能吗?

c# - C#winform-如何删除多个DataGridViewRows

c# - 紧凑框架中的透明度

c# - C++ dll 似乎无法在 .NET 中正常工作

javascript - 将 js 转换为 C# 时出现 System.OverflowException