【问题标题】:Why is the MemoryStream data not released from memory为什么 MemoryStream 数据没有从内存中释放
【发布时间】:2009-05-19 20:42:37
【问题描述】:

下面的代码需要做些什么来释放它使用的内存吗?

  Dim objImage As MemoryStream
  Dim objwebClient As WebClient
  Dim sURL As String = Trim(m_StationInterface.PicLocation)

  objwebClient = New WebClient
  objImage = New MemoryStream(objwebClient.DownloadData(sURL))
  m_imgLiftingEye.Image = Image.FromStream(objImage)

代码位于一个不应被丢弃的弹出表单上。每次弹出时都会将新图像加载到表单上。但是,每次通过该代码块时,应用程序的进程大小都会继续增长。

我已经尝试过 objImage.Close() 和 .Flush()、objWebClient.Dispose()。每次调用后,进程大小仍会增长 4mb。就像旧图像被保存在内存中一样。

【问题讨论】:

    标签: vb.net memory-management memorystream


    【解决方案1】:

    Image 实现了 IDisposable,因此您应该先处置旧图像,然后再将其替换为新图像。

    类似的东西(请耐心等待,我有一段时间没有使用 VB):

    Dim objImage As MemoryStream
    Dim objwebClient As WebClient
    Dim sURL As String = Trim(m_StationInterface.PicLocation)
    
    objwebClient = New WebClient
    objImage = New MemoryStream(objwebClient.DownloadData(sURL))
    
    If m_imgLiftingEye.Image Is Not Nothing Then
        m_imgLiftingEye.Image.Dispose()
    End If
    m_imgLiftingEye.Image = Image.FromStream(objImage)
    

    【讨论】:

    • 我的代码看起来一模一样,而且进程大小还在增长。
    • 我认为他需要这样做我的回答。
    【解决方案2】:

    试试这个:

    Function GetImage() As Image
        Using wc As New WebClient(), _
              ms As New MemoryStream(wc.DownloadData(m_StationInterface.PicLocation.Trim())
    
            GetImage = Image.FromStream(ms).Clone()
        End Using
    End Function
    

    【讨论】:

    • 顺便说一句,克隆是一个聪明的主意。制作函数也是如此。
    【解决方案3】:

    MemoryStream 实现了 IDisposable 接口,因此您应该在使用完毕后对该对象调用 Dispose:

    objImage = New MemoryStream(objwebClient.DownloadData(sURL))
    m_imgLiftingEye.Image = Image.FromStream(objImage)
    objImage.Dispose()
    

    我猜你的结论是对的;图像(在内存流中)确实保留在内存中。

    更新:正如 Marc 指出的那样,Image.FromStream 要求流在图像的生命周期内保持打开状态。为了解决这个问题,应该在与图像相同的范围内声明 MemoryStream 变量(作为表单中的字段)。加载图像时,首先应该检查 MemoryStream 是否已经打开,如果是,则在将变量用于新流之前关闭并释放它(假设我们称之为 m_imageStream)。由于图像也实现了 IDisposable,因此该图像也是如此:

    If Not m_imageStream Is Nothing Then
        m_imageStream.Dispose()
    End If
    
    If m_imgLiftingEye.Image Is Not Nothing Then
        m_imgLiftingEye.Image.Dispose()
    End If
    
    m_imageStream = New MemoryStream(objwebClient.DownloadData(sURL))
    m_imgLiftingEye.Image = Image.FromStream(m_imageStream)
    

    【讨论】:

    • 我不相信 MemoryStream 实现了 IDisposable。
    • 这也是我的第一个想法,但查看 Image 类的 FromStream() 文档:“您必须在 Image 的整个生命周期内保持流打开。”这不好;我建议缓存图像并从中加载 Image 类,而不是在请求生命周期的某个时刻保留多个需要处理的对象。
    • hypoxide:System.IO.Stream 实现了 IDisposable,MemoryStream 继承了它。
    • 我已经用我尝试过的代码示例更新了我的帖子,并且发现它可以工作。 R. Bemrose 和我有点攻击同一个目标,但是针对不同的对象:Image 和 Stream 都需要处理。 (好几年没写VB代码了,很有趣的经历)
    • 我知道你在做什么,但 m_imageStream 是什么?此外,MemoryStream 在那里被声明。我认为它应该从无开始?
    【解决方案4】:

    我知道我已经给出了一个答案,但从那以后我一直在思考......

    您说过永远不应该处理此表单。在那种情况下,这个图像加载到底是什么时候发生的?我之前的回答假设它是在表单显示事件期间。但是,如果是在表单Load 事件期间,它应该只发生一次。

    也就是说,除非创建了多个表单实例。如果是这种情况,并且之前的表单没有被重用,那么您最终会在内存中加载同一个表单的多个副本,每个副本都有自己的图像副本。

    【讨论】:

    • 我也想过这个问题,但创建对话框的唯一位置是在加载期间。
    • 也可以是Activated事件。
    【解决方案5】:

    你可以试试

    set objImage = nothing
    set objwebClient = nothing
    

    通常,与 ADO 一样,如果您没有将其显式设置为空,则它不会被正确释放。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2018-11-08
      • 2016-07-19
      • 2012-10-10
      • 2021-10-03
      • 2015-06-14
      • 1970-01-01
      相关资源
      最近更新 更多