Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/295.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 为什么这个内存没有被清理,或者根本没有被分配?_C#_Garbage Collection - Fatal编程技术网

C# 为什么这个内存没有被清理,或者根本没有被分配?

C# 为什么这个内存没有被清理,或者根本没有被分配?,c#,garbage-collection,C#,Garbage Collection,所以,我有一个很棒的程序非常有用: static void Main(string[] args) { new Dictionary<int,int>(10000000); while (true) { System.Threading.Thread.Sleep(1000); } } static void Main(字符串[]args) { 新字典(10000000); while(true) { 系统线程线程睡眠(1000);

所以,我有一个很棒的程序非常有用:

static void Main(string[] args)
{
    new Dictionary<int,int>(10000000);

    while (true)
    {
        System.Threading.Thread.Sleep(1000);
    }
}
static void Main(字符串[]args)
{
新字典(10000000);
while(true)
{
系统线程线程睡眠(1000);
}
}
这甚至不会从编译器中产生任何警告,这是令人惊讶的

运行此命令将分配一块内存。如果我运行多个副本,我最终会到达无法再启动的地步,因为我的内存已用完

  • 为什么垃圾收集器从不清理内存,而是让系统进入没有足够内存用于新进程的状态
  • 见鬼,为什么内存分配没有优化呢?它永远不能被任何东西引用
    这是怎么回事

    垃圾收集器是不确定的,并对内存压力做出响应。如果不需要内存,它可能暂时无法收集。它不能优化掉
    新的
    ,因为这会改变你的代码:构造函数可能有副作用。此外,在调试中,它更有可能决定不收集

    在发布/优化的构建中,我希望在有充分理由的时候收集这些信息。还有
    GC.Collect
    ,但除了极端情况或某些评测需求外,通常应该避免这种情况


    作为一个“原因”——GC“世代”之间的GC行为存在差异;在“大对象堆”(LOH)上有一些大数组。保持检查这个LOH非常昂贵,这也许可以进一步解释为什么它如此不情愿。

    我不知道这是事实,但我猜这是因为即使没有创建对新词典的引用,它也已链接到本地范围,而您的程序永远不会离开。要检查是否存在这种情况,只需在内部作用域中创建字典,您可以在开始循环之前将其保留,例如

    static void Main(string[] args) { { new Dictionary(10000000); } while (true) { System.Threading.Thread.Sleep(1000); } } 静态void Main(字符串[]参数) { { 新字典(10000000); } while(true) { 系统线程线程睡眠(1000); } }
    这将使内存可用于垃圾收集

    我猜正在进行隐藏的Gen0收集

    这是我的测试程序:

    static void Main(string[] args)
    {
        new Dictionary<int, int>(10000000);
        Thread.Sleep(5000);
    
        int x = 1; // or 0;
        int i = 0;
        while (true)
        {
            object o = ++i;
            Thread.Sleep(x);
        }
    }
    
    static void Main(字符串[]args)
    {
    新字典(10000000);
    睡眠(5000);
    int x=1;//或0;
    int i=0;
    while(true)
    {
    对象o=++i;
    睡眠(x);
    }
    }
    
    当系统执行Sleep(1)时,系统必须认为这是只在Gen0上进行快速隐藏GC的好时机。因此,“object o=++i”语句不会对Gen0施加压力,也不会触发GC集合,因此也不会释放字典

    将x更改为0。现在,这个隐藏的GC没有发生,事情按照预期进行,“object o=++i”语句导致收集字典


    GC可能会运行并释放内存。。。对于应用程序本身。也就是说,如果
    Sleep()
    调用需要分配一些RAM,那么它可能会找到大量的RAM,即最初分配给大型
    字典的大块

    这并不意味着GC将内存返回给操作系统。从操作系统的角度来看,大模块可能仍然是进程的一部分,不可由任何其他进程使用


    分配没有优化,因为它是一些外部代码。你的
    Main
    类为
    Dictionary
    调用一个构造函数,它可以做任何可能有各种副作用的事情。作为一名人类程序员,您希望构造函数不会有外部可见的副作用,但编译器和虚拟机并不确定这一点。因此,代码不能不真正创建一个
    字典
    实例并调用其构造函数。类似地,
    字典
    构造函数不知道调用它的对象很快将变得不可访问,因此它无法对自身进行优化。

    您正在运行调试还是优化的构建程序。。为什么这会有什么不同。。。。IL在这里是相同的;没有本地的etc,只有“流行音乐”。即使有一个变量,IL局部变量的作用域也不像C#变量(它们都是在方法的开头声明的)。实际上,这不会有一点区别。这些内部语句块对编译器来说实际上是透明的——生成的IL看不到它们。