将memoryStream作为字符串返回

时间:2010-03-26 11:35:40

标签: c#

这句话有什么问题?

return Encoding.ASCII.GetString(memoryStream.GetBuffer(), 0, memoryStream.Length)

我知道Dispose模式,检查了底层的memoryStream,发现在dispose中没有发生任何事情。那么为什么我不允许我的开发人员这样做呢。

返回后,memoryStream超出范围。

目的是使代码简洁而不创建不需要的引用,希望尽快让垃圾收集器启动。

它只是让我感到唠叨,我觉得memoryStream让对方失望,与其他流做的相比,以及为什么他们实现了IDispose。

有人可以给我一个很好的理由不允许上面的代码。我对代码不正确但需要一些备份感到胆怯。 :)

**** **** WeNeedAnswers :编辑请注意由于Jon Skeets的输入,代码已经改变,但这个问题的主要核心仍然是相关的。

我原始且容易出错的代码是:

return new ASCIIEncoding().GetString(memoryStream.ToArray());

4 个答案:

答案 0 :(得分:5)

就我个人而言:

string text;
memoryStream.Position = 0;
using (TextReader reader = new StreamReader(memoryStream, Encoding.ASCII))
{
    text = reader.ReadToEnd();
}

作为一种更通用的方式 - 但您的代码至少应该起作用。如果您的目标是不创建超出需要的对象,则应使用Encoding.ASCII而不是创建新实例。如果你真的偏执于复制,你可以使用:

string text = Encoding.ASCII.GetString(memoryStream.GetBuffer(),
                                       0, memoryStream.Length);

这样可以避免创建数据副本。

您似乎关心内存使用情况 - 您有什么理由吗?您是否进行过分析并发现垃圾收集是一个瓶颈?如果没有,请不要担心,直到您 发现它是一个问题。通常不是。

答案 1 :(得分:1)

  

“希望很快让垃圾收集者尽快开始。”

我将给出一个简短且过于简化的GC入门,因为你似乎并不欣赏它是如何工作的......

首先, GC不具有确定性。它并没有“尽快”开始;它通常会在内存压力下开始。因此,无论您在方法中执行什么操作,都无法保证它将在方法结束时或在任何其他特定时间运行。通常,当GC Generation 0中没有足够的空间来分配新对象时,GC将运行。

其次,如果您未在Dispose上致电MemoryStream(手动或using阻止), GC将无法释放该内存,即使它运行。当你打电话给一个典型的Dispose时,会发生两件事:首先,对象被整理,第二次调用GC.SuppressFinalize。后一个调用很重要:它告诉GC你已经为对象做了清理。

如果没有在您的对象上调用Dispose,那么GC会将您的对象放在“Finalizer队列”上。这是一个等待整理的对象队列。如果您的对象最终在此队列上,则无法释放,因为队列保持活动状态。这意味着您的对象将被推送到GC第1代,并且不会因批次更长时间而被清除。在收集第0代并且无法发布的对象不适合第1代之前,GC生成1将不会被收集。对于大多数应用,对于一个GC gen-1,比率大约为10 GC gen-0收集收集,所以你不用调用Dispose就可以将对象的寿命延长10倍。

故事的道德:如果一个类型实现了IDisposable,并且你担心内存使用(甚至只是关于良好的编程习惯),调用Dispose方法。这是有原因的。

第三:即使您明智地致电Dispose内存版本仍然不具有确定性,因为您所做的只是确保 next GC将会发布记忆。

最后:不要试图自己致电GC.Collect这几乎总是一件坏事,通常会导致你的应用程序更高内存占用,而不是较低的内存。

答案 2 :(得分:1)

MemoryStream实现了IDisposable,因为它继承自更通用的Stream类。但实际上没有必要在此调用Dispose()。

Dispose()函数的要点是告诉类清理它可能获得的任何非托管资源。对于FileStream,它将是文件句柄和文件锁。但MemoryStream只分配内存,因此没有必要对其进行处理。当你的内存流超出范围时,无论你是否调用Dispose(),都可以进行垃圾收集。

但通常情况下,你应该总是在实现IDisposable的对象上调用Dispose(),并且允许异常可能会在没有彻底了解正在发生的事情的开发人员之间造成混淆。

我认为您的一些担忧来自对.NET内存和垃圾收集模型的不了解。我从书中Applied Microsoft .NET Framework Programming了解到了这一点。这是一本针对.NET 1.0的古老书籍,但关于内存管理和垃圾收集的部分非常值得一读。

答案 3 :(得分:-1)

您将在内存中的流中最终得到两个字节副本。另外,谁说处置的实施不会改变?还有,现在你有一个bigass字符串。

如果您担心的是GC,为什么要使用相同字节的两个副本和一个巨大的字符串强奸它?