我已经使用内存流来下载文件。文件下载后,我需要清除该内存流使用的所有内存。
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);
}
}
将文件发送到响应后,它不会释放正在被占用的内存。它几乎占用了文件大小的两倍。 17 MB文件占用近40 MB内存。
应该采取什么措施来释放这些空间。 我试图清除字节数组,但发现它只替换了数组的每个元素,0保持其长度相同。
答案 0 :(得分:2)
为避免双重缓冲,不要拨打.ToArray()
;相反,您可以通过ms.GetBuffer()
访问现有缓冲区。请注意,这是超大的,因此您可能需要使用:
context.Response.BinaryWrite(ms.GetBuffer(), 0, ms.Length);
请注意,您无法确定地告诉数组消失,Array.Clear
没有您想要的效果。清理是垃圾收集器的工作,你不应该经常搞乱。
然而!更好的方法是不能一次性读取所有内容,而是使用纯流式方法。我不知道你的DecryptAndStoreInMemory
是如何实现的,所以我不知道你的情况是否可行,但是:它通常是。
答案 1 :(得分:1)
在.NET framwerk中,您无法直接控制内存使用情况。您的内存由垃圾收集器(GC)控制。当你处理了你的流并最终被解除引用后,它被称为 dead 。这意味着它可以用于垃圾收集,当内存压力过高时会自动进行垃圾收集。
在绝大多数情况下,这里不需要任何优化,因为仅仅因为使用了内存,并不意味着它在垃圾收集期间无法释放。使用GC的托管内存也不需要比非托管内存慢,因为与非托管内存(如果有足够的可用内存)相比,托管内存中新对象的分配速度很快,因为托管内存未分段。
您可以使用GC.Collect()
启动垃圾回收,但这可能会使您的代码更少高性能,而不是自动运行垃圾回收。启动集合不一定会减少已使用的内存大小,因为GC并不总是将释放的内存返回给操作系统。