为什么我必须明确地调用GC收集?

时间:2013-04-22 08:05:06

标签: c# .net

我创建了一个示例C#控制台应用程序,它以字节数组的形式读取文件数据并将字节数组转换为十六进制字符串。它需要巨大的内存,并且在工作完成后不会释放内存,我也在使用中的变量无效。

以下是示例代码:

string filename = @"F:\\AVSEQ09.DAT"; //file size is 32 MB
string hexData = null;

byte[] fileDataContent = File.ReadAllBytes(filename);
if (fileDataContent != null)
    hexData = BitConverter.ToString(fileDataContent);
fileDataContent = null;
hexData = null;

//GC.Collect();
Console.ReadKey();

如果我运行此代码需要433 MB的私有工作集,如果我取消注释GC.collect调用,则memmory降至6 MB。为什么我必须明确地调用GC.collect,明确调用GC.collect是不好的,如何在不调用GC.collect的情况下释放内存(为6 MB)?

6 个答案:

答案 0 :(得分:9)

Garbage collection is the simulation of infinite memory on a machine with finite memory,通过回收有效程序无法注意到的内存丢失。

以上是一个非常重要的概念,因为它突出了这样一个事实:垃圾收集器不会做任何事情,只要它可以在每次程序要求时提供内存它

它可能不是最可控的内存管理系统,但如果您的程序最终处于内存压力的情况下,CLR通常会自动启动垃圾收集周期以减轻一些压力。当系统似乎没有受到压力时,系列会被推迟,以避免频繁的不必要的暂停。

答案 1 :(得分:4)

您无需明确致电GC.Collect

您的代码确实使用了大量内存,但是垃圾收集有一个智能算法,可以确定它应该运行的时间。它在内存不足或内存使用量突然增加时运行。只要剩下额外的内存,垃圾收集器就不会做任何事情。这大大提高了性能。如果GC不断运行,你的表现会很糟糕。

在.NET中也不需要将变量设置为null。运行时将跟踪正在使用的变量,并在必要时将其标记为集合。

答案 2 :(得分:2)

您不应明确使用GC,而应避免一次性读取所有数据。 这是你正在执行的相当糟糕的练习......当从文件中读取时,你应该使用using - 语句并在小缓冲区中读取。

using(StreamReader sr = new StreamReader(filename)){
     //while has data
     char[] buffer = new char[64000]; // or whatever you like
     sr.ReadBlock(buffer, 0, buffer.Length);     
     //do your conversion here
}

StreamReader.ReadBlock()查看{{1}}。

答案 3 :(得分:1)

.NET CLR管理内存本身,并在必要时调用垃圾收集器。

无论如何,即使您拥有时间紧迫的代码,也可以依赖.NET CLR在适当的时候调用垃圾收集器。 GC非常高效,可以非常快速地释放内存。

所以确实没有问题。不要打电话给GC,你不需要。这是.NET。

答案 4 :(得分:1)

当您处理这些大文件和内存结构时,请考虑使用流而不是打开并转换内存中的完整文件。无论如何你不应该打电话给GC收集。

答案 5 :(得分:1)

.NET垃圾收集器是一代分类收集器。从世代的角度来看,大型对象(85K或更大)属于第2代,因为它们仅在存在第2代集合时收集,其中包括所有生成,这不会像第0代集合那样经常发生因为对象大小,大对象通常是数组(在你的情况下是byte [])。第2代集合可以通过以下方式引起:

  • 分配超过第0代或大对象阈值大多数GC因为托管堆上的分配而发生
  • 系统处于低内存状态当我收到时,会发生这种情况 来自操作系统的高内存通知。
  • 调用System.GC.Collect当有人调用GC.Collect时 第2代(通过传递没有参数到GC.Collect或传递 GC.MaxGeneration作为参数)

因此,当你的系统需要内存时,它会正常地释放字节数组而不强迫它通过调用GC.Collect释放它。

查看this article