如何在base64转换后释放内存
我正在尝试流式传输文件的内容。 该代码适用于较小的文件,但对于较大的文件,我会收到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()
。
如何为转换后的字符串释放内存?
从这里编辑下来…这是一个更新。 我还创建了一个关于此的新线程 – 抱歉,我想这不是正确的事情。
谢谢你的好建议。 根据建议,我缩小了用于从文件中读取的缓冲区大小,看起来内存消耗更好,但我仍然看到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之外的东西,因为潜在的大内容? 能够创建请求的整个有效负载似乎非常方便。
这完全是错误的方法吗? 我希望能够支持非常大的文件。
如果使用32 kB或更高的BLOCK_SIZE
,则将创建85 kB或更大的字符串,这些字符串在大对象堆上分配。 短命对象应该存在于常规堆中,而不是大对象堆中,这可能是存储器问题的原因。
另外,我发现代码有两个潜在的问题:
请记住,在将数据转换为base64时,生成的字符串将延长33%(假设输入大小为3的倍数,这在您的情况下可能是个好主意)。 如果BLOCK_SIZE太大,则可能没有足够的连续内存来保存生成的base-64字符串。
尝试减少BLOCK_SIZE,以便base-64的每个部分都更小,从而更容易为它分配内存。
但是,如果您使用像StringWriter这样的内存中TextWriter,则可能会遇到同样的问题,因为它无法找到足够大的内存块来容纳内部缓冲区。 如果你正在写一个类似文件的东西,这应该不是问题。
疯狂猜测… HttpWebRequest.AllowWriteStreamBuffering默认为true,根据MSDN“将AllowWriteStreamBuffering设置为true可能会导致上传大数据集时出现性能问题,因为数据缓冲区可能会使用所有可用内存”。 尝试设置oRequest.AllowWriteStreamBuffering = false
,看看会发生什么。
尝试将base64String声明拉出循环。 如果仍然没有帮助,请尝试在经过多次迭代后调用垃圾收集器。
所以GC.Collect(); GC.WaitForPendingFinalizers();
尝试减小块大小或避免将Convert调用的结果赋给变量:
bytesRead = inputStream.Read(base64Block, 0, base64Block.Length); tw.Write(Convert.ToBase64String(base64Block, 0, bytesRead));
从内存使用的角度看代码看起来不错,但我认为你正在为基于内存的流(如MemoryStream)传递编写器,并在那里存储数据会导致OOMexception。
如果BLOCK_SIZE高于86Kb,则会在大对象堆(LOH)上进行分配,它将改变分配行为,但不应自行引起OOM。
注意:您的结束条件不正确 – 应该是bytesRead!= 0,在genral中,即使剩下更多数据,Read也可以返回比询问更少的字节。 据我所知,FileStream永远不会这样做。
我会先将结果写入临时文件。
上述就是C#学习教程:如何在base64转换后释放内存分享的全部内容,如果对大家有所用处且需要了解更多关于C#学习教程,希望大家多多关注—计算机技术网(www.ctvol.com)!
using (TextWriter tw = new StreamWriter(oRequest.GetRequestStream())) { tw.Write(strHead); var tempPath = Path.GetTempFileName(); try { using (var input = File.OpenRead(strPath)) using (var output = File.Open( tempPath, FileMode.Open, FileAccess.ReadWrite)) { StreamEncode(fileStream, output); output.Seek(0, SeekOrigin.Begin); CopyTo(output, ((StreamWriter)tw).BaseStream); } } finally { File.Delete(tempPath); } tw.Write(strTail); } public void StreamEncode(Stream inputStream, Stream output) { // For Base64 there are 4 bytes output for every 3 bytes of input byte[] base64Block = new byte[9000]; int bytesRead = 0; string base64String = null; using (var tw = new StreamWriter(output)) { 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 ); } } static void CopyTo(Stream input, Stream output) { const int length = 10240; byte[] buffer = new byte[length]; int count = 0; while ((count = input.Read(buffer, 0, length)) > 0) output.Write(buffer, 0, count); }
本文来自网络收集,不代表计算机技术网立场,如涉及侵权请联系管理员删除。
ctvol管理联系方式QQ:251552304
本文章地址:https://www.ctvol.com/cdevelopment/1016506.html