代码之家  ›  专栏  ›  技术社区  ›  Daniel Sam

为什么会导致内存泄漏?

  •  0
  • Daniel Sam  · 技术社区  · 16 年前

    这很有趣。我们花了最后一天的时间试图修补以下(遗留)代码的问题,这些代码会继续增加其进程大小。这是在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()
    

    现在。我们尝试过很多事情。我们已经发现,处置什么都不起作用,而且,事实上, IDisposable 接口实际上不接触内存。如果我们不每次创建一个新的CJ5Form ptoPeratorAcknowledge表单,则流程大小不会增长。但是,将新图像加载到该表单中仍然会导致进程大小不断增长。

    任何建议都将不胜感激。

    2 回复  |  直到 13 年前
        1
  •  2
  •   user79755    16 年前

    您必须释放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
    
        2
  •  0
  •   JP Alioto    16 年前

    我不知道为什么会发生泄漏,但我可以建议您使用 .NET Memory Profiler . 如果您使用它运行应用程序,它将使您非常清楚哪些对象没有被处理,并帮助您解决问题。它有一个免费试用版,但很值得购买。