为啥这会导致内存泄漏?
Posted
技术标签:
【中文标题】为啥这会导致内存泄漏?【英文标题】:Why Is This Causing a Memory Leak?为什么这会导致内存泄漏? 【发布时间】:2009-05-21 17:45:28 【问题描述】:这很有趣。我们花了最后一天尝试使用以下(遗留)代码修补问题,该代码继续增加其进程大小。这是在 Visual Studio 2003 中完成的。
我们有一个显示图像(来自 MemoryStream)、一些文本和一个按钮的表单。没有什么花哨。看起来像这样:
Protected Overrides Sub OnLoad(ByVal e As System.EventArgs)
MyBase.OnLoad(e)
Try
m_lblWarning.Visible = False
m_grpTitle.Text = m_StationInterface.ProcessToolTitle
m_lblMessage.Text = m_StationInterface.ProcessToolMessage
Dim objImage As MemoryStream
Dim objwebClient As WebClient
Dim sURL As String = Trim(m_StationInterface.ProcessToolPicLocation)
objwebClient = New WebClient
objImage = New MemoryStream(objwebClient.DownloadData(sURL))
m_imgLiftingEye.Image = Image.FromStream(objImage)
m_txtAcknowledge.Focus()
Catch ex As Exception
'*** This handles a picture that cannot be found without erroring'
m_lblWarning.Visible = True
End Try
End Sub
此表单经常关闭和打开。每次重新打开时,进程内存使用量大约增加 5mb。当表单关闭时,它不会回退到以前的用法。资源仍然分配给未引用的表单。表单呈现如下:
m_CJ5Form_PTOperatorAcknowlegement = New CJ5Form_PTOperatorAcknowlegement
m_CJ5Form_PTOperatorAcknowlegement.stationInterface = m_StationInterface
m_CJ5Form_PTOperatorAcknowlegement.Dock = DockStyle.Fill
Me.Text = " Acknowledge Quality Alert"
'*** Set the size of the form'
Me.Location = New Point(30, 30)
Me.Size = New Size(800, 700)
Me.Controls.Add(m_CJ5Form_PTOperatorAcknowlegement)
该控件稍后在关闭后从表单中移除:
Me.Controls.Clear()
现在。我们已经尝试了很多东西。我们发现 Disposing 什么都不做,事实上,IDisposable 接口实际上并没有触及内存。如果我们不每次都创建一个新的 CJ5Form_PTOperatorAcknowledgement 表单,则进程大小不会增长。但是将新图像加载到该表单中仍然会导致进程大小不断增长。
任何建议将不胜感激。
【问题讨论】:
【参考方案1】:您必须处置您的 WebClient 对象和任何其他可能不再需要的托管非托管资源。
objImage = New MemoryStream(objwebClient.DownloadData(sURL))
objwebClient.Dispose() ' add call to dispose
一种更好的编码方式是使用“using”语句:
using objwebClient as WebClient = New WebClient
objImage = New MemoryStream(objwebClient.DownloadData(sURL))
end using
如需更多信息,请在 google 和 *** 上搜索“Dispose”和“IDisposable”模式实现。
最后一个提示:尽可能不要使用内存流。除非您需要将其保存在 RAM 中,否则直接从文件加载图像。
编辑
如果我正确理解您的代码,也许这样的事情会起作用:
Dim objImage As MemoryStream
Dim objwebClient As WebClient
Dim sURL As String = Trim(m_StationInterface.ProcessToolPicLocation)
using objwebClient as WebClient = New WebClient
using objImage as MemoryStream = New MemoryStream(objwebClient.DownloadData(sURL))
m_imgLiftingEye.Image = Image.FromStream(objImage)
end using
end using
【讨论】:
直到 Visual Studio 2005 才添加“使用”语句。处理不是这里的问题。我们已经尝试了几乎所有的对象处理变体,但都没有成功。我们还尝试存储文件的本地副本,而不是使用内存流。 你在使用 COM 对象吗?您可能需要在您的 COM 对象上调用 System.Runtime.InteropServices.Marshal.ReleaseComObject? 不涉及 COM 对象。到目前为止唯一有效的是重用相同的表单对象,而不是每次都实例化一个新的对象。如果我们不必每次都将新图像加载到表单上(这仍然会增加进程大小),那将是一个解决方案。就好像垃圾收集器无法识别不再引用旧对象一样。我们甚至可以在表单上省略任何功能性内容,并且流程规模仍在增长。 嗯,有很多变量,没有足够的上下文让我在这里继续猜测,但我会说你尝试过 Form.Dispose、Image.Dispose 等,等等......任何你的资源新的'你应该'处置'。此外,垃圾收集器会在自己的时间运行,您不会看到立即释放内存。如果您已覆盖“最终确定”,则可能会延长该内存的保留时间。 除了处理表单等...确保您手动删除使用“addhandler”添加的任何事件处理程序。【参考方案2】:我不知道具体为什么会泄漏,但我可以建议您使用.NET Memory Profiler。如果你使用它来运行你的应用程序,它会让你很好地了解哪些对象没有被释放,并帮助你解决原因。它有免费试用版,但值得购买。
【讨论】:
以上是关于为啥这会导致内存泄漏?的主要内容,如果未能解决你的问题,请参考以下文章
为啥 Netty ByteBuf.readBytes 会导致内存泄漏?