Board logo

標題: 求教有關UserForm使用完後不佔記憶體的清除方法 [打印本頁]

作者: clio    時間: 2016-3-25 18:03     標題: 求教有關UserForm使用完後不佔記憶體的清除方法

各位前輩,不好意思,又要來發問了
假如我自己作了一個UserForm1而,要開啟的他方法又有二種
方法一:
Sub Test_1()

    Dim AForm As UserForm1

    Set AForm = New UserForm1
   
    With AForm
        
        .Show
   
    End With
   
    Unload AForm
    Set AForm = Nothing
   
End Sub

方法二
Sub Test_2()

    UserForm1.Show
   
    Unload UserForm1

End Sub

想請教各位前輩的是:
一、在方法一內Unload AForm,這時視窗會消失,但是算是連佔用的記憶體都清掉了嗎?還是要再執行Set AForm = Nothing才會清掉記憶體呢?
二、另外我要是沒有執行Unload AForm,只執行Set AForm = Nothing,似乎視窗還在,但是理論上來說AForm佔用的記憶體應該
被清掉才對
三、這二種方法,有什麼優缺點之分別嗎?
作者: luhpro    時間: 2016-3-26 00:16

本帖最後由 luhpro 於 2016-3-26 00:21 編輯

回復 1# clio
以下是 Excel VBA 的說明 :
一般當使用 Set 來引用物件給變數時,
並非複製一份物件給變數,
而是建立一份對該物件的引用
(註 : 這裡所謂的引用, 最簡單的例子就是Excel活頁簿中某個儲存格的位址, 藉由這個位址可以引用到<取得>此儲存格的內容,字型...)
超過一個以上的物件變數可以引用相同的物件。
因為變數是引用該物件,
而不是引用該物件的複製品,
該物件若改變,
則所有引用它的變數也會跟著改變。
然而,若在 Set 陳述式上使用 New 關鍵字,
則會真的建立該物件的執行個體。 (註 : 雖然建立了 一個物件, 該變數仍然還是一份對該物件的引用)

所以 Set AForm = Nothing 其實只是清空該變數 (失去引用功能),
完全沒有動到該物件的本體.

至於 Unload  的說明 :
將一個物件自記憶體中移除。
顧名思義.

其實除非在程式執行過程中才動態建立物件,
否則當開啟檔案後記憶體內就已存了一份該物件的資料了.
最簡單的驗證方式 -
開啟Excel 存檔重開看看使用的記憶體空間量,
接著加個UserForm後存檔重開再看看使用的空間量,
會發現即使沒用程式 Load 或 Show 照樣使用的空間會較多.
當然若 Load 或 Show 了後空間會用更多.
作者: stillfish00    時間: 2016-3-28 15:13

回復 1# clio
個人覺得 unload 是寫在 form events(如click) 內要關閉、釋放自己這個表單用的。
而不是像你寫在 show 下面,你這樣寫可能會有不良效果。

例如你的方法二,
如果在 UserForm_Initialize() 加一行 MsgBox "Hi",你猜它會被呼叫幾次?
答案是兩次!!
第一次是發生在 UserForm1.Show,因為前面沒明確寫出 Load (這是允許的),VBA自動幫你load建立Form。
然後因為你按表單的 x 關閉時,UserForm1已經釋放掉了,所以當你執行到 Unload UserForm1 ,VBA又自動幫你建立Form,再釋放掉。

而方法一,是把 UserForm1當物件類別用
我覺得吧, set ... = new ...,就是取代 Load 作用,Unload AForm我是不知道有沒有效果。
物件的記憶體不用太糾結,印象中 VBA 應該是採用 garbage collector 機制,計算引用次數 (reference count),當引用次數為零就會找時機回收記憶體了。
既然AForm是區域變數,離開那個Sub 就釋放了(也就是不引用了),這裡甚至加不加Set AForm = Nothing都無所謂。

我的話,要嘛按鈕內做完一些事直接 unload me關閉視窗,要嘛就都不加 unload,手動按X關閉視窗。
有錯請指正喔~
作者: jackyq    時間: 2016-3-28 17:28

New 用來產生多個實例

Sub QX9650()

Load UserForm1
UserForm1.Caption = "Form_1"
UserForm1.Show 0
tt = tt + 30: UserForm1.Top = tt
MsgBox "Load Form x1 -> Form count " & UserForms.Count

Load UserForm1
UserForm1.Caption = "Form_2"
UserForm1.Show 0
tt = tt + 30: UserForm1.Top = tt
MsgBox "Load Form x2  -> Form count " & UserForms.Count

Load UserForm1
UserForm1.Caption = "Form_3"
UserForm1.Show 0
tt = tt + 30: UserForm1.Top = tt
MsgBox "Load Form x3  -> Form count " & UserForms.Count

Set F1 = New UserForm1
F1.Caption = "Form_111"
F1.Show 0
tt = tt + 30: F1.Top = tt
MsgBox "New Form x1-> Form count " & UserForms.Count

Set F2 = New UserForm1
F2.Caption = "Form_222"
F2.Show 0
tt = tt + 30: F2.Top = tt
MsgBox "New Form x2 -> Form count " & UserForms.Count

Set F3 = New UserForm1
F3.Caption = "Form_333"
F3.Show 0
tt = tt + 30: F3.Top = tt
MsgBox "New Form x3 -> Form count " & UserForms.Count

End

End Sub
作者: jackyq    時間: 2016-3-28 17:39

Set AForm = Nothing,似乎視窗還在
因為視窗的本體 VB 還偷偷滴咬著他
所以不會被釋放
作者: clio    時間: 2016-3-29 10:57

回復 2# luhpro

感謝前輩的解說,這個太清楚了,讓我更清楚的明白,Set 的意義,感謝您。
作者: clio    時間: 2016-3-29 11:08

回復 3# stillfish00

感謝前輩的指正跟說明,讓我更清楚的了解了一些事,我本來是考慮建立一個空白的UserForm,然後再用一個Function來呼叫它,而所有的載入資料,頡取回覆資料都由這個Function來處理取得,而Function又可以傳回資料,所以我就可以得到使用者選取的資料為何,而Function內載入的一些參數,可以決定ListBox的值,與一些選項參數,我也打算讓他成為強制選取,所以會取消✕按鍵的功能,使它失效,因為目前我找不到更好的方法來讓UserForm結束前,把使用者選取的資料傳出出來,目前只能用Public變數才能達到,但是我有些不想設這樣多Public 變數,所以才想改用此一方式。
作者: clio    時間: 2016-3-29 12:02

回復 4# jackyq

前輩的這個例子,解釋的很清楚說,前面三個LoadForm1都是重新LoadForm1,所以統計UserForm2.Count都為1
而後三個Set F1=New UserForm1,則是建立了另一個UserForm1,所以UserForm2.Count就會再加1
感謝前輩的例子




歡迎光臨 麻辣家族討論版版 (http://forum.twbts.com/)