2008-11-05 129 views
2

有沒有這樣的事情?VB6中的動態內存分配

我在談論類似於C++ new命令的內容,即分配需要顯式釋放內存的內存(或風險內存泄漏)。

我問,因爲我記得有通過表單/控制/其他對象設置爲Nothing以前解決一些GDI泄漏問題,但不記得是什麼,或者爲什麼現在......

我們曾經擔心在VB6中開發時的內存管理?

回答

7

就VB6中的內存管理而言,有幾個方面值得關注。

第一個是循環引用,其中子類指向父代,反之亦然。如果沒有明確地將引用設置爲Nothing,那麼有時對於表單來說也是如此,特別是對象是Target對象的編輯器。再次確保一切設置爲無效將解決問題。

基本原理是1)如果對象指向的任何東西是「活着的」,那麼它將不會被垃圾收集。因此,當您將引用設置爲循環引用的父對象時,該子節點處於活動狀態,因此父節點不會收集垃圾信息,因爲父節點仍處於活動狀態,所以子節點不會收集垃圾信息。

與表格相同。如果您沒有將編輯對象的對話框的目標屬性設置爲無效,只要目標對象處於活動狀態,它就不會觸發最後一系列事件。

這樣做的最常見的副作用是你的應用程序將無法正常關閉和你的內存佔用量將增長的應用程序使用的時間越長。

至於GDI泄漏,任何時候您使用使用句柄,指針的外部DLL。您將自己置於與C++相同的領域,以實現這些功能。所以你必須確保你遵循你使用的特定API或DLL的所有規則,這些規則通常包括明確地銷燬你在完成之後創建的那些規則。

對於循環參考問題,有一個優雅的解決方案。而不是孩子直接引用父母,你使用代理。

首先做一個代理類的父對象。

Option Explicit Public Event GetRef(ByRef RHS As MyObject) 

Public Function GetMyObject() As MyObject 
    Dim Ref As MyObject 
    RaiseEvent GetRef(Ref) 
    Set GetMyObject = Ref 
End Function 

然後是在父

Private WithEvents MyProxy As MyObjectProxy 

Private Sub Class_Initialize() 
    Set MyProxy = New MyObjectProxy 
End Sub 

然後安裝稱爲代理的只讀屬性來定義一個私有變量並實現GetRef事件。

Public Property Get Proxy() As MyObjectProxy 
    Set Proxy = MyProxy 
End Property 

Private Sub MyProxy_GetRef(RHS As MyObject) 
    Set RHS = Me 
End Sub 

對於需要參考的代碼如下孩子或其他任何東西。

Private ParentProxy As MyObjectProxy 

Public Property Get Parent() As MyObject 
    If ParentProxy Is Nothing Then 
     Set Parent = Nothing 
    Else 
     Set Parent = ParentProxy.GetRef 
    End If 
End Property 

Public Property Set Parent(RHS As MyObject) 
    If RHS Is Me Then 
     Set MyObjectProxy = Nothing 
    ElseIf Target Is Nothing Then 
     Set MyObjectProxy = Nothing 
    Else 
     Set MyObjectProxy = RHS.Proxy 
    End If 
End Property 

因爲事件機制不設置引用或增加在任一COM引用計數反對它避免了整個循環引用的問題,是許多VB6程序員的禍根。

注:我是從源稱這是代理,但由於安東尼的評論,我覺得這也符合調解模式的定義。它使用特定的VB6中心功能; Event API並不完全符合Mediator Pattern的精神。

另外還要認識到在.NET框架有等同VB6的事件API雖然它實現方式不同(代表等)

+0

這就是衆所周知的中介模式,值得添加到這個答案的文本。 – AnthonyWJones 2008-11-06 10:20:43

3

我想說你永遠不必擔心內存管理,但這不是真的。它在一定程度上取決於你的VB6代碼運行的執行環境。當然,我已經看到了在COM +下運行的VB6類,如果它們完成時沒有顯式地將對象引用設置爲Nothing,將會泄漏內存。

除了環境問題外,您在VB6類型系統中分配的內存通常會爲您清理。我正在談論您使用New關鍵字分配的內容。但有一個重要的例外,由rpetrich和其他人指出: -

由於VB用於管理分配對象的生存期的引用計數機制,如果您有任何循環引用,則可能會泄漏內存。例如,A-> B-> C-> A。如果你有這種情況,你可能需要自己發現它,並通過明確地將引用設置爲Nothing來治癒它。我沒有意識到任何有助於識別這類問題的工具。

當您使用其他語言編寫的庫時,會出現其他問題。你可能會新建一個用C++編寫的COM對象,它在內部分配一些內存,並發現你必須調用特定的方法(如Close)來釋放內存。也許這樣一個COM對象會寫得很糟糕,但其中很多都存在。

因此,有沒有規律可循,除非是: -

  1. 嘗試儘可能多地瞭解你使用任何圖書館的行爲,並
  2. 始終運行你的代碼,而觀看存儲在性能監視器中進行跟蹤以確保其內存使用量不會以無限制的方式增長。
  3. 嘗試瞭解循環引用;-)
+0

由於VB6(和COM通常)使用參考計數,所以能夠泄漏經由圓形物體引用。你應該編輯你的第二段來反映這 – rpetrich 2008-11-05 18:15:03

3

是的,我曾與各種形式的simmilar的問題,所以我將它們明確不了了之每個卸載。

但主要與第三方控件的問題似乎有時不是所有的COM引用在正確清除。

看一看here