C# 正在使用的干净内存

C# 正在使用的干净内存,c#,asp.net,performance,memory,optimization,C#,Asp.net,Performance,Memory,Optimization,我已经用内存流下载了这个文件。一旦文件被下载,我需要清除该内存流使用的所有内存 context.Response.BufferOutput = true; //DecryptAndStoreInMemory decrypt a requested file and store in memory using (MemoryStream ms = DecryptAndStoreInMemory(context.Server.MapPath(path), userFileName)) {

我已经用内存流下载了这个文件。一旦文件被下载,我需要清除该内存流使用的所有内存

context.Response.BufferOutput = true;
//DecryptAndStoreInMemory decrypt a requested file and store in memory
using (MemoryStream ms = DecryptAndStoreInMemory(context.Server.MapPath(path), userFileName))
    {
      byte[] bytesInStream = ms.ToArray();
      context.Response.ContentType = "application/octet-stream";
      context.Response.AddHeader("Content-Length", bytesInStream.Length.ToString());
      context.Response.AddHeader("Content-Disposition", "attachment; filename=" + userFileName);
      ClearStream(ms);
      context.Response.BinaryWrite(bytesInStream);
      context.Response.Flush();
      context.Response.Close();
      Array.Clear(bytesInStream, 0, bytesInStream.Length);
    }


ClearStream(MemoryStream stream)
{
    if(stream != null)
    {
        stream.Flush();
        stream.Close();
        stream.Dispose();
    }
}
//解密文件并存储在内存流中

public MemoryStream DecryptAndStoreInMemory(string inputFilePath, string userFileName)
{
    MemoryStream msOutput = null;
    if (File.Exists(inputFilePath))
    {
        try
        {
            using (Aes encryptor = Aes.Create())
            {
                Rfc2898DeriveBytes pdb = new Rfc2898DeriveBytes(_password, _salt);
                encryptor.Key = pdb.GetBytes(32);
                encryptor.IV = pdb.GetBytes(16);
                using (FileStream fsInput = new FileStream(inputFilePath, FileMode.Open))
                {
                    using (CryptoStream cs = new CryptoStream(fsInput, encryptor.CreateDecryptor(), CryptoStreamMode.Read))
                    {
                        using (msOutput = new MemoryStream())
                        {
                            int data;
                            while ((data = cs.ReadByte()) != -1)
                            {
                                msOutput.WriteByte((byte)data);
                            }
                        }
                    }
                }
            }
            return msOutput;
        }
        catch (CryptographicException)
        {
            throw new Exception("Sorry we can not serve " + userFileName + " file at this time.");
        }
        catch (Exception)
        {
            throw;
        }
    }
    else
    {
        throw new Exception("Sorry we could not locate " + userFileName);
    }

}
文件发送到响应后,不会释放占用的内存。这几乎是文件大小的两倍。17MB的文件占用了近40MB的内存

应该做些什么来腾出这些空间。
我试图清除字节数组,但发现它仅用0替换数组中的每个元素,使其长度保持不变。

在.NET framwerk中,您无法直接控制内存使用。内存由垃圾收集器(GC)控制。当您处理了您的流并且它最终被解除引用时,它被称为dead。这意味着它将进行垃圾收集,当内存压力过高时,垃圾收集将自动发生

在绝大多数情况下,这里不需要任何优化,因为仅仅因为使用了内存,并不意味着在垃圾收集期间无法释放内存。带有GC的托管内存也不一定比非托管内存慢,因为托管内存中的新对象分配比非托管内存快(如果有足够的可用内存),因为托管内存是不分段的


您可以使用
GC.Collect()
初始化垃圾收集,但这可能会使代码的性能低于自动运行垃圾收集。而且,启动收集并不一定会减少已用内存的大小,因为GC并不总是将释放的内存返回给操作系统。

在.NET framwerk中,您无法直接控制内存的使用。内存由垃圾收集器(GC)控制。当您处理了您的流并且它最终被解除引用时,它被称为dead。这意味着它将进行垃圾收集,当内存压力过高时,垃圾收集将自动发生

在绝大多数情况下,这里不需要任何优化,因为仅仅因为使用了内存,并不意味着在垃圾收集期间无法释放内存。带有GC的托管内存也不一定比非托管内存慢,因为托管内存中的新对象分配比非托管内存快(如果有足够的可用内存),因为托管内存是不分段的


您可以使用
GC.Collect()
初始化垃圾收集,但这可能会使代码的性能低于自动运行垃圾收集。并且启动一个收集并不一定会减少您使用的内存大小,因为GC并不总是将释放的内存返回给操作系统。

为了避免双重缓冲,不要调用
.ToArray()
;相反,您可以通过
ms.GetBuffer()
访问现有缓冲区。请注意,这是超大尺寸的,因此您可能需要使用:

context.Response.BinaryWrite(ms.GetBuffer(), 0, ms.Length);
请注意,您无法确定地告诉数组离开,并且
array.Clear
没有您想要的效果。清理是垃圾收集器的工作,你通常不应该弄乱它



然而!一个更好的方法是根本不要一次读取所有内容,而是:使用纯流式方法。我不知道您的
DecryptAndStoreInMemory
是如何实现的,所以我无法判断这在您的情况下是否可行,但是:通常是这样。

为了避免双重缓冲,不要调用
.ToArray()
;相反,您可以通过
ms.GetBuffer()
访问现有缓冲区。请注意,这是超大尺寸的,因此您可能需要使用:

context.Response.BinaryWrite(ms.GetBuffer(), 0, ms.Length);
请注意,您无法确定地告诉数组离开,并且
array.Clear
没有您想要的效果。清理是垃圾收集器的工作,你通常不应该弄乱它



然而!一个更好的方法是根本不要一次读取所有内容,而是:使用纯流式方法。我不知道您的
DecryptAndStoreInMemory
是如何实现的,所以我无法判断在您的情况下这是否可行,但是:通常是这样。

第一道防线是垃圾收集器。如果变量
ByteInstream
不再在任何地方引用,则应收集该变量并释放内存。这还假设
bytesInStream
是真正的麻烦制造者。你能试着插入
GC.Collect()吗
GC.WaitForPendingFinalizers()?在内存分析过程中,当您稍等一点时,内存消耗是否会变得更好?@MaximilianGerhardt我确实在顶部和底部编写了GC.Collect(),这会导致在下一次请求相同文件时清理内存。如果我再次请求同一个文件,那么它会释放以前使用过的内存,并再次保留内存。第一道防线是垃圾收集器。如果变量
ByteInstream
不再在任何地方引用,则应收集该变量并释放内存。这还假设
bytesInStream
是真正的麻烦制造者。你能试着插入
GC.Collect()吗
GC.WaitForPendingFinalizers()?在内存分析过程中,当您稍等一点时,内存消耗是否会变得更好?@MaximilianGerhardt我确实在顶部和底部编写了GC.Collect(),这会导致在下一次请求相同文件时清理内存。如果我再次请求同一个文件,那么它会释放以前使用的内存,并再次保留内存。我已编辑了我的问题,并添加了
DecryptAndStoreInMemory
方法。请看一看,让我们知道未来的任何增强。以及关于上述
context.Response.BinaryWrite(ms.GetBuffer(),0,ms.Length)我没有得到带有3个输入参数的
BinaryWrite
方法。我只有一个采用
byte[]
的方法。我已经编辑了我的问题,并添加了
DecryptAndStoreInMemory
方法。请看一下并让我们知道