StreamReader.ReadToEnd导致大量内存使用/泄漏

时间:2014-03-07 14:00:15

标签: c# .net memory-management

它的作用:对于每个EncryptedBase64PictureFile,读取内容,解密base64字符串并创建一个图片框。

问题出在哪里:疯狂内存使用!我猜每个循环后的一些数据都没有被正确删除。例如,输入大约100MB加密数据的100个循环(应生成大约100MB的图像文件)使用大约1.5 GB的内存!当我尝试解密更多的数据,大约150MB时,我得到OutOfMemory异常。 Visual Studio的内存分析报告称,“string fileContent = reader.ReadToEnd();” line负责80%的分配。

for each EncryptedBase64PictureFile {
    Rijndael rijAlg = Rijndael.Create();
    rijAlg.Key = ASCIIEncoding.ASCII.GetBytes(sKey);
    rijAlg.IV = ASCIIEncoding.ASCII.GetBytes(sKey);
    FileStream fsread = new FileStream(EncryptedBase64PictureFile, FileMode.Open, FileAccess.Read);
    ICryptoTransform desdecrypt = rijAlg.CreateDecryptor();
    CryptoStream cryptostreamDecr = new CryptoStream(fsread,desdecrypt, CryptoStreamMode.Read);

    StreamReader reader = new StreamReader(cryptostreamDecr);
    string fileContent= reader.ReadToEnd(); //this should be the memory eater
    var ms = new MemoryStream(Convert.FromBase64String(fileContent));

    PictureBox myPictureBox= new PictureBox();
    myPictureBox.Image = Image.FromStream(ms);

    ms.Close();
    reader.Close();
    cryptostreamDecr.Close();
    fsread.Close();

}

所以问题是,有没有办法在每次循环后正确处理内存?或者其他问题是什么? 每个想法的Thanx!

编辑: 当然我试图处理()所有4个流,但结果是相同的......

ms.Dispose();
reader.Dispose();
cryptostreamDecr.Dispose();
fsread.Dispose();

编辑: 发现问题。它不是dispose(),而是从流中创建图片。删除图片后,内存使用量从1.5GB增加到20MB。

编辑: 图片大约是500kb的.jpg格式,大约700kb的base64加密格式。但我真的不知道,影像箱对象有多大。

编辑: 输入大约100MB的100个循环意味着每个循环大约需要1MB,100个循环总共100MB

2 个答案:

答案 0 :(得分:1)

另一个答案:和它一起生活。

如下所示:您在看似32位应用程序的情况下使用100mb块。如果没有重用缓冲区,由于大对象堆和一般内存碎片,这将无法工作。

如下:内存在那里,只是没有足够大的块。这会导致分配错误。

没有真正的解决办法,除了64位,较大的地址空间处理问题。

有关此信息,请访问:

https://connect.microsoft.com/VisualStudio/feedback/details/521147/large-object-heap-fragmentation-causes-outofmemoryexception

https://www.simple-talk.com/dotnet/.net-framework/large-object-heap-compaction-should-you-use-it/

现在有一个可能的解决方案,可以实现大对象堆的结合:

GCSettings.LargeObjectHeapCompactionMode = GCLargeObjectHeapCompactionMode.CompactOnce;
GC.Collect(); // This can be omitted

LOH的选择很费劲,但是运行aruond的100mb区域并不完全是GC的推荐方案。不是32位。

答案 1 :(得分:0)

解密您的信息流时使用base 64转换。不要使用Convert.FromBase64String,因为这需要所有数据都在内存中。

using (FileStream f64 = File.Open(fileout, FileMode.Open) ) // content is in base64
using (var cs=new CryptoStream(f64, new FromBase64Transform(), CryptoStreamMode.Read ) ) // transform passed to constructor
using(var fo =File.Open(filein +".orig", FileMode.Create))
{
    cs.CopyTo(fo); // stream is accessed as if it was already decrypted
}   

从相关答案中取得的代码示例 -  Convert a VERY LARGE binary file into a Base64String incrementally