c#如何删除循环中分配的内存?

时间:2013-04-06 09:50:06

标签: c#

想象一下这段代码:

int i=9999999;
while ( i > 1 )
{
    string UnusedMemory="this is a string that eats some ram" + i.ToString();
    i--;
}

如果仅在运行GC.Collect()时删除了未引用的对象,则此代码应分配大量的ram,直到收集发生。但它根本没有分配大量内存,为什么呢?在IL级别上是否有某种“删除”?或者GC.Collect()自动调用更快?我知道这是一个简单的例子,但是如果它更复杂并且在该代码块中访问了字符串,那么无论如何都不会吃掉很多ram。

编辑:我更改了示例,以便字符串始终是唯一的,因此无法“缓存”

2 个答案:

答案 0 :(得分:8)

字符串常量在字符串池中“缓存”,因此每次都是相同的字符串。

如果您对字符串使用方法String.IsInterned,那么它将返回true,这意味着它包含在池中。

来自String.IsInterned

  

公共语言运行库自动维护一个名为的表   实习池,包含每个唯一的单个实例   在程序中声明的文字字符串常量,以及任何唯一的   您以编程方式添加的String实例。

     

实习池保存了字符串存储空间。如果您指定文字   字符串常量为几个变量,每个变量都设置为   在实习池中引用相同的常量而不是引用   几个具有相同值的String的不同实例。

此外,当需要内存或分配了足够的元素时,会自动调用GC,因此即使字符串没有被缓存,也不会有问题。

来自Fundamentals of Garbage Collection

当满足下列条件之一时,就会发生垃圾收集:

  • 系统物理内存不足。
  • 托管堆上已分配对象使用的内存超过了可接受的阈值。这意味着托管堆上已超出可接受内存使用量的阈值。随着流程的运行,此阈值会不断调整。
  • 调用GC.Collect方法。几乎在所有情况下,您都不必调用此方法,因为垃圾收集器会持续运行。此方法主要用于独特的情况和测试。

是否可以更改此行为或对其进行优化? 是的,在某种程度上:Latency Modes

这个问题与以下内容非常相关: C# memory usage for creating objects in a for loop

答案 1 :(得分:3)

当从堆中分配对象,并且没有足够的可用空间时,垃圾收集器将运行。如果第一个堆的集合没有释放足够的内存,它将继续在下一级堆上执行集合。只有当所有堆的集合都没有释放足够的内存时,它才会从系统中分配更多的内存。

由于您的示例中有许多最近释放的对象,因此第一个堆的集合将始终释放足够的内存。你的循环会多次填满堆。您可以在循环之前和之后打印GC.CollectionCount(0)以查看它运行的次数。