对C#static / const成员/局部变量有疑问。只想知道在C#中分配给未使用的static / const成员/局部变量的内存会发生什么,在以下示例场景中如何回收内存?
问题是关于静态和常量变量的内存行为[考虑每个应用程序域内存 - 静态存储]?这个问题与垃圾收集无关。它是关于内存以及未使用的静态和const变量会发生什么?(也)有内存?
Spaghetti Code代码段:
/// <summary>
/// Skew your data with every-second-and-annoyed updates
/// </summary>
class Skewgle
{
static Skewgle cloneApele = new Skewgle();
const Skewgle patentMoto = default(dynamic);
static int? dontBeEvilMotto = 1998;
const int ditchMotoToBeEvil = 2014;
static void Main()
{
const Skewgle findYourMailsAlreadyReadBetweenSpamTabs = patentMoto;
if (findYourMailsAlreadyReadBetweenSpamTabs == null)
{
System.Console.WriteLine("findYourMailsAlreadyReadBetweenSpamTabs and patentMoto are null");
}
if (cloneApele != null)
{
System.Console.WriteLine("cloneApele is not null");
}
System.Console.WriteLine("What about dontBeEvilMotto? ditchMotoToBeEvil?");
}
}
由于
答案 0 :(得分:5)
在首次使用类的任何实例/静态方法(static field initialization in C# spec)之前,将初始化类的所有静态字段。
静态字段是每个应用程序域,在卸载AppDomain之前,不会为GC标记值。
答案 1 :(得分:4)
MSDN:http://msdn.microsoft.com/en-us/library/e6w8fe1b.aspx
常量表达式是一个可以在编译时完全计算的表达式。因此,引用类型常量的唯一可能值是string和null。
所以你不能让patentMoto
成为null
以外的任何东西。顺便说一句。 default(dynamic)
完全返回null
。你可以在那里写下=null
,这样阅读会更简单。除<{1}}之外,永远不会具有任何非空“const对象变量”。但是你可以有大量的string
s。
static
和const
永远不会GC,直到卸载内存中的AppDomain为止。
GC定义清除了不再引用的所有内容。由于静态变量会记住某个对象,因此只要static
变量存在,就不会清除该对象。并且只要包含Type“exists”就存在,因此只有在卸载AppDomain时它才会存在。除非你创建自己的额外appdomains并在某个时间点“手动”卸载它们,否则意味着它们会在程序的出口处被清除。
但是,这是指自动清理static
变量记住的内容。您可以使用早期发布的thigs - 只需要static
ify静态变量。 GC扫描对象,而不是变量。 (*)
显然,null
不可能,因此任何大的const
字符串都会永远占用内存。关于AppDomain - 对于const
它更难:它们实际上被编译到程序集中。因此,只有在从内存中卸载程序集后才能完全清理它们。如果程序集在appdomains之间共享,那么它将一直保留到最后一个被删除。 Const是只读和不可变的,所以分享它不应该是一种痛苦。请记住,所有对象const变量都是const
或字符串。没有其他选择。因此,除非您创建一个4-Gb const字符串,否则您不必担心。
null
没有任何区别。它是一个本地“变量”,但它仍然编译成原始程序集。见上文。
(*)这意味着如果你创建一个包含一百万(1000000)个静态变量的类,全部为null,那么它们的存在将占用至少~4MB的内存,直到app域被卸载。那是因为要保留一百万个无效指针。在这种情况下,GC没有任何内容,只有Type本身。
答案 2 :(得分:2)
const和static之间的主要区别在于内存的位置。 所有const数据都与可执行代码(只读存储器(ROM))位于相同的存储空间中,其中静态数据被加载到动态存储器中,您可以在其中读取和写入。 现在这里是有趣的部分,似乎在以前的每个答案中都被忽略了。 静态数据占用动态内存空间但需要额外的ROM空间,在更糟糕的情况下,可能占用两倍的内存量。 请考虑以下事项:
class StaticData
{
static readonly int s_static1 = 1;
static readonly int s_static2 = 2;
}
class ConstData
{
const int CONST1 = 1;
const int CONST2 = 2;
}
类StaticData有两个静态变量s_static1和s_static2,它们将占用2个整数的动态内存空间。但是它们都需要初始化,因此必须存在ROM代码来初始化它们。在这个例子中,根据编译器,至少需要2个字节(或2个没有优化的存储整数)ROM空间,只需存储2个常数值(1&amp; 2)来初始化静态变量,更不用说初始化它们所需的可执行ROM代码。
对于ConstData类,只需要ROM存储空间,因此在大多数情况下,这是内存的最佳使用。
现在,当您考虑编译器如何使用数据时,它会变得更有趣。除字符串/字符数据外,常量通常直接在引用的代码中替换。换句话说,根据使用情况,常量值直接加载到寄存器中或压入堆栈。在静态变量的情况下,编译器必须通过附加代码(指针引用)从存储器中读取该值,因此需要额外的ROM代码。
总而言之,使用“const”代替“static readonly”几乎总是更好。