C#静态和常量变量存储器

C#静态和常量变量存储器,c#,C#,对C#静态/常量成员/局部变量有疑问。只想知道分配给C#中未使用的静态/常量成员/局部变量的内存会发生什么情况,在下面的示例场景中,如何回收内存 问题是关于静态和常量变量的内存行为[考虑每个应用程序域内存-静态存储]?这个问题与垃圾收集无关。这是关于内存的问题,以及(也)有内存的未使用的静态变量和常量变量会发生什么情况 意大利面条代码段: /// <summary> /// Skew your data with every-second-and-annoyed updates //

对C#静态/常量成员/局部变量有疑问。只想知道分配给C#中未使用的静态/常量成员/局部变量的内存会发生什么情况,在下面的示例场景中,如何回收内存

问题是关于静态和常量变量的内存行为[考虑每个应用程序域内存-静态存储]?这个问题与垃圾收集无关。这是关于内存的问题,以及(也)有内存的未使用的静态变量和常量变量会发生什么情况

意大利面条代码段:

/// <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?");
    }
}
//
///每秒钟都会扭曲数据,并使更新变得恼火
/// 
类歪斜
{
静态Skewgle cloneaple=新Skewgle();
const Skewgle patentMoto=默认值(动态);
静态int?Dontbeevilmont=1998;
const int DITCHOTOBEEVIL=2014;
静态void Main()
{
const Skewgle findyourmailsalreadyreadtween spamtabs=patentMoto;
如果(FindYourMailsAllReadyReadBeweensPamTabs==null)
{
System.Console.WriteLine(“在Samtabs和patentMoto之间的FindYourMailsReadyReadyRead为空”);
}
if(cloneApele!=null)
{
System.Console.WriteLine(“cloneapel不为空”);
}
System.Console.WriteLine(“DontBeevill呢?ditchMotoToBeEvil呢?”);
}
}
感谢

在首次使用类()的任何实例/静态方法之前,将初始化类的所有静态字段

静态字段是每个应用程序域的字段,在卸载AppDomain之前,不会为GC标记值。

MSDN:

常量表达式是可以在编译时完全计算的表达式。因此,引用类型的常量的唯一可能值是string和null

因此,您不能让
patentMoto
null
以外的任何内容。顺便说一句,
default(动态)
精确返回
null
。你可以在那里写
=null
,这样读起来更简单。除了
字符串
,您将永远不会有任何非空的“const object variable”。但是你可以有大量的
static
s

const
static
在内存中包含它们的AppDomain卸载之前,不会被GC'ed

根据定义,GC将清除不再引用的所有内容。由于静态变量记住某个对象,因此只要
静态变量存在,就不会清除该对象。只要包含类型“存在”,它就存在,因此只有在卸载AppDomain时它才会停止存在。除非您创建自己的额外AppDomain并在某个时间点“手动”卸载它们,否则这意味着它们将在程序退出时被清除

但是,这是指自动清理
静态变量所记住的东西。您可以让thigs更早地发布—只需
null
ify静态变量即可。GC扫描对象,而不是变量。(*)

显然,
const
是不可能的,因此任何大的
const
字符串都会永远占用内存。关于AppDomain-For
const
更难:它们实际上是编译到程序集中的。因此,只有在从内存中卸载程序集后,它们才会被完全清除。如果程序集在appdomains之间共享,那么它将一直保留到最后一个被删除为止。Const是只读的和不可变的,所以无论如何分享它都不会让人感到痛苦。请记住,所有对象常量变量都是
null
或字符串。没有其他选择。因此,除非您创建一个4-Gb常量字符串,否则您不必担心这个问题

本地范围内的const
没有任何不同。它是一个局部“变量”,但仍编译到原始程序集中。见上文


(*)这意味着,如果创建一个包含一百万(1000000)个静态变量的类,所有静态变量都为空,那么它们的存在将消耗至少4MB的内存,直到卸载应用程序域。那是因为要保留一百万个空指针。在这种情况下,GC没有什么,只有类型本身。

常量和静态的主要区别在于内存的位置。 所有常量数据都位于与可执行代码相同的内存空间中,即只读内存(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个常量值(1和2)至少需要2个字节(或2个存储整数,无需优化)的ROM空间,更不用说初始化静态变量所需的可执行ROM代码了

对于ConstData类,只需要ROM存储空间,因此在大多数情况下,这是内存的最佳使用

<>现在,当你考虑编译器如何使用数据时,它会变得更有趣。除字符串/字符数据外,常量通常直接在代码中的引用点处替换。换句话说,常量值直接加载到寄存器中或推送到堆栈上,具体取决于使用情况。对于静态变量,编译器必须通过附加代码(指针引用)从内存中读取该值,因此需要附加ROM代码

总之,你几乎总是比我强