2013-04-08 12 views
0

我与vb.net下面的代码:.NET内存泄漏,使用GC.Collet()或者不

Public Async Function WriteData(buffer() As Byte, offset As Integer, count As Integer) As System.Threading.Tasks.Task 
     Try 
      Using data_writer = IO.WindowsRuntimeStreamExtensions.AsStreamForWrite(_outputStream) 
       Await data_writer.WriteAsync(buffer, offset, count) 
       Await data_writer.FlushAsync 
      End Using 
     Catch ex As Exception 
      Logger.Write(ex) 
     End Try 
    End Function 

我调用该函数WriteDate太多,但我注意到在增加内存每次我调用函数,因为您可以看到datawriter流和_outputStream被处置,因为使用Using。

当我运行vs Profiler时,分析器显示95%的内存被我的代码中的“buffer”字节数组保留过多。

1-您是否在我的代码中看到任何问题? 2-如何清除字节数组?

- 我下面的代码添加到该函数的行等待data_writer.FlushAsync

buffer = Nothing 
GC.Collect() 

所以我的记忆不会像以前那样增加后,但我打电话写数据太多我的应用程序,和我请阅读,建议不要调用GC.Collect太多。

不调用GC.Collect,内存跳转到300 MB,GC.Collect()内存不超过50MB。

请指教。

谢谢

回答

2

这是一个通用的GC问题,并非针对Phone或Await。尽管它肯定无助于解决问题。问题是你的缓冲区太大,超过85KB。太大以至于很容易被GC压缩,因此它被分配到大对象堆中。现在第0代中没有足够的小对象来触发集合。 LOH只在gen#2集合中被清除,因此调用GC.Collect()确实是一种解决方法。

避免必须调用Collect()的两个基本策略。首先强烈支持使用更小的缓冲区,小到足以在#0中分配。做一点工作总是更好,等待关键字应该确实有助于在代码中做出微小的改变。很难说,我们看不到来电者。

第二个策略是重用缓冲区,所以你只需要其中的一个。这又是多么容易取决于呼叫者的样子。

+0

许多感谢@Hans,真是一个非常好的解决方案。 1-分裂缓冲区小于85K可能会降低性能和速度2-我如何重新使用缓冲区? – Sameh 2013-04-08 11:45:07

+0

不,不存在由于小缓冲区I/O会明显减慢的情况。除非你使缓冲区小于一千字节。注意过早优化,特别是在手机上。一个好的缓冲区大小是4096字节。我无法帮助您弄清楚如何重用缓冲区,我看不到调用此方法的代码。 – 2013-04-08 11:59:08

+0

非常感谢@Hans你的回答是公平的,谢谢你的时间。 – Sameh 2013-04-08 12:06:17

2

您应该在尝试控制GC之前了解GC的工作方式。垃圾收集主要由“内存压力”驱动也就是说,当你的程序缺乏即时使用的内存时,为了释放一些内容,将会发生一个集合。

不调用GC.Collect,您的内存使用量为300MB的原因是因为.NET在运行代码时没有承受压力。因为它没有压力,所以它不会浪费时间来运行一个集合。 300MB的分配内存没有被主动使用 - 只是因为你打电话给Collect,你的代码并不是神奇的效率 - 但是没有理由在这一点上进行整理。

我的建议是:不要拨GC.Collect,除非你有一个特定的和有意义的理由来减少你的应用程序的内存使用。当需要时,垃圾收集器将自己收集该内存(您可能会看到您的使用量增加,然后定期回落至〜50MB)。

+1

谢谢,但有一段时间我的应用程序关闭,因为内存达到300 MB,在WP8项目上工作,并且存在内存限制。甚至分析器都会警告我关于内存中保留的字节。 – Sameh 2013-04-08 11:02:41

+1

在你的问题中提到这可能是有用的:-) – 2013-04-08 11:22:35

+0

我很抱歉@丹Puzey忘记提及。 – Sameh 2013-04-08 11:41:57

0

我有同样的问题,在其他情况下,与HTTP服务器,但我找到了真正的解决方案:

不要从不使用AsStreamForWrite(),直接使用WinPRT IOuputStream(我想这是可能的,即使在VB) AsStreamForWrite()创建一个内部流,它只是吃了内存(在几种情况下)并且从不释放它。

+0

亲爱的@Poppyto,你有没有AsStreamForWrite的问题的证明,或者它是为了你自己的经验? – Sameh 2014-08-28 08:17:33

+1

验证是经验:我花了72小时处理大内存泄漏(本地Web服务器“代理”文件),当我删除AsStreamForWrite并直接使用WinPRT对象时,我没有更多内存泄漏。我知道这不是我的错,因为内存分析器证实它不是.NET内存问题(所以本机内存问题!),所以忘记GC.Collect和其他。 – Poppyto 2014-08-28 12:22:34