3

因此,我使用了一个 StreamReader,它使用 MemoryStream 写入 StreamWriter 和此应用程序内部,但内存使用量增加了 300mb(来自较大的输入之一),并且在我完成使用后不会取消分配:

StreamWriter log = new StreamWriter("tempFile.txt");
log.Write(reader.ReadToEnd());
log.Close();

reader.DiscardBufferedData();
reader.Close();
reader.Dispose();
memoryStream.Dispose();
log.Dispose();
GC.Collect();

在此之前和之后,我得到了 RAM 使用量,之前它比之后少 300 mb,但我不知道为什么。考虑到这里唯一发生的事情是来自阅读器的数据被放置在文本文件中,我已经做了我能想到的一切来释放该内存我不明白为什么甚至需要使用任何大量内存暂时地。我有什么遗漏吗?...谢谢。

4

4 回答 4

6

您是否正在查看进程本身使用的 RAM?我没想到会下降。该进程将保留该内存并重用它以进行进一步的分配。它不会将其交还给操作系统。这正是 .NET 的工作方式。

可能会通过一些 CLR API 调用来丢弃内存 - 但通常我不会。

这并不意味着内存真的泄漏了——它仍然可以被同一个进程使用。例如,如果您再次执行相同的操作,它可能不需要增加堆的大小 - 您会看到内存使用率在进程级别保持不变。使用 CLR 性能图查看托管堆中使用的内存,以查看是否存在真正的泄漏。

(对于应用程序实际使用的内存量也有多种不同的衡量标准。哪一个有趣取决于您要执行的操作。)

编辑:如果您的代码片段真正表明您正在使用的代码,那么有一个更简单的选择:流数据。

using (TextWriter writer = File.CreateText("tempFile.txt"))
{
    CopyText(reader, writer);
}

static void CopyText(TextReader reader, TextWriter writer)
{
    char[] buffer = new char[8192];
    int charsRead;
    while ((charsRead = reader.Read(buffer, 0, buffer.Length)) > 0)
    {
        writer.Write(buffer, 0, charsRead);
    }
}

请注意,除非您实际更改编码,否则您可以在不使用TextWriter/TextReader对开始的情况下执行此操作。

这样您就不需要将整个字符串及其二进制表示形式(在MemoryStream. 当然,您仍然拥有二进制表示 - 您是否必须将所有内容都写入MemoryStream开始?

于 2010-06-22T16:24:56.343 回答
2

除了 Jon 发布的内容之外,.NET 运行时的行为方式为您提供了一些重要的好处- 保持为进程分配的内存是一件好事,除非系统内存不足(在这种情况下,运行时可能会释放它)。

例如,如果您经常需要分配大量内存(如您在此处发布的方法),那么如果进程已经分配了内存(即使它不用于存储任何 .NET 对象),效率会更高. 下次运行他的方法,分配会快很多!

无论如何,您可以做的几件事是:

  • 您可以尝试运行另一个内存密集型应用程序,以查看运行时是否在系统需要时释放内存
  • You can use some .NET profiler to see whether there are any live objects that you would expect to be collected after running the method
于 2010-06-22T16:27:04.827 回答
0

我不确定它是否会有所帮助,但请尝试一些using范围界定:

using (StreamReader reader = new StreamReader(somestream))
using (StreamWriter log = new StreamWriter("tempFile.txt"))
{
    log.Write(reader.ReadToEnd());
}
于 2010-06-22T16:25:33.917 回答
0

In the segment mentioned above, all of log, reader, and memoryStream are still in scope and so can't be garbage collected. I don't know what the implmentation of Dispose on those objects is, but it's entirely likely that they're still holding much of the data in memory even after Dispose is called (since Dispose typically only closes filehandles, unmanaged memory, and such, and doesn't necessarily delete internal buffers). If you want this to work as expected, you have to let all of the referenced objects go out of scope and become unreferenced.

Really, though, you shouldn't worry about this unless memory usage is causing you explicit pain.

于 2010-06-22T16:27:10.700 回答