【发布时间】:2011-03-25 17:36:02
【问题描述】:
我正在尝试流式传输文件的内容。 该代码适用于较小的文件,但对于较大的文件,我会收到 Out of Memory 错误。
public void StreamEncode(FileStream inputStream, TextWriter tw)
{
byte[] base64Block = new byte[BLOCK_SIZE];
int bytesRead = 0;
try
{
do
{
// read one block from the input stream
bytesRead = inputStream.Read(base64Block, 0, base64Block.Length);
// encode the base64 string
string base64String = Convert.ToBase64String(base64Block, 0, bytesRead);
// write the string
tw.Write(base64String);
} while (bytesRead == base64Block.Length);
}
catch (OutOfMemoryException)
{
MessageBox.Show("Error -- Memory used: " + GC.GetTotalMemory(false) + " bytes");
}
}
我可以隔离问题并观察使用的内存在循环过程中增长。
问题似乎是对Convert.ToBase64String() 的调用。
如何为转换后的字符串释放内存?
从这里开始编辑......这是一个更新。 我还为此创建了一个新的 thread —— 抱歉,我想这不是正确的做法。
感谢您的精彩建议。根据建议,我缩小了用于从文件读取的缓冲区大小,看起来内存消耗更好,但我仍然看到 OOM 问题,而且我看到文件大小小至 5MB 时出现此问题。我可能想处理十倍大的文件。
我现在的问题似乎在于使用 TextWriter。
我创建一个请求如下 [通过一些编辑来缩小代码]:
HttpWebRequest oRequest = (HttpWebRequest)WebRequest.Create(new Uri(strURL));
oRequest.Method = httpMethod;
oRequest.ContentType = "application/atom+xml";
oRequest.Headers["Authorization"] = getAuthHeader();
oRequest.ContentLength = strHead.Length + strTail.Length + longContentSize;
oRequest.SendChunked = true;
using (TextWriter tw = new StreamWriter(oRequest.GetRequestStream()))
{
tw.Write(strHead);
using (FileStream fileStream = new FileStream(strPath, FileMode.Open,
FileAccess.Read, System.IO.FileShare.ReadWrite))
{
StreamEncode(fileStream, tw);
}
tw.Write(strTail);
}
.....
调用例程:
public void StreamEncode(FileStream inputStream, TextWriter tw)
{
// For Base64 there are 4 bytes output for every 3 bytes of input
byte[] base64Block = new byte[9000];
int bytesRead = 0;
string base64String = null;
do
{
// read one block from the input stream
bytesRead = inputStream.Read(base64Block, 0, base64Block.Length);
// encode the base64 string
base64String = Convert.ToBase64String(base64Block, 0, bytesRead);
// write the string
tw.Write(base64String);
} while (bytesRead !=0 );
}
由于潜在的大内容,我应该使用 TextWriter 以外的东西吗?能够创建请求的整个有效负载似乎非常方便。
这完全是错误的方法吗?我希望能够支持非常大的文件。
【问题讨论】:
-
你不应该捕捉 OutOfMemoryException (事实上,在 .NET4 中,你不能,至少不诉诸 syntactic salt )。现在,关于这个问题...... BLOCK_SIZE 是什么,您使用的是什么 TextWriter,以及读取了多少字节?其中一项或多项可能是罪魁祸首。
-
我添加了 try/catch 来帮助诊断这个问题。这不是我最初写的方式。
-
BLOCK_SIZE 的值为 54000。我将其减小到 30000,但内存仍在增长——但现在需要更多循环,因为它更小了。
-
块大小可能是 32kB 或更大,在 LOH 中产生了太多的大字符串。较小的尺寸很好,Convert.ToBase64CharArray() 最好。
标签: c# memory-leaks out-of-memory