【问题标题】: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 表单,则进程大小不会增长。但是将新图像加载到该表单中仍然会导致进程大小不断增长。

任何建议将不胜感激。

【问题讨论】:

    标签: vb.net visual-studio memory-leaks visual-studio-2003


    【解决方案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 和 stackoverflow 上搜索“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。如果你使用它来运行你的应用程序,它会让你很好地了解哪些对象没有被释放,并帮助你解决原因。它有免费试用版,但值得购买。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2022-01-03
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多