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看不到它们。