我有一个非常简单的表单,它使用一个非常简单的类来处理某些事情。该类有一个Class_Terminate
子项可以自己清除。但是,关闭表单后似乎并没有触发。
MCVE:
Form 1,一个名为Text0的文本框,没有其他控件
Private myClass1 As Class1
Private Sub Form_Load()
Set myClass1 = New Class1
myClass1.InitForm Me
End Sub
Class Class1
Public theForm As Form
Private WithEvents SomeTextbox As TextBox
Public Sub InitForm(frm As Form)
Set theForm = frm
Set SomeTextbox = frm.Text0
End Sub
Private Sub Class_Terminate()
MsgBox "Class1 terminated succesfully"
End Sub
但是,当我关闭表单时,类终止处理程序不会触发。
我尝试取消该类中的 Form 对象:
Private Sub Form_Unload(Cancel As Integer)
Set myClass1.theForm = Nothing
End Sub
但是随之而来的是混乱:类终止处理程序在关闭表单后触发,但是之后立即访问而没有任何错误消息!
答案 0 :(得分:5)
在关闭表单时Access无法正常清理表单对象。
这意味着:如果对象具有对表单的开放引用,则该表单对象将保留。如果没有引用,则只能由垃圾收集器将其删除。
该表单的第一个版本造成了内存泄漏:表单对象Form_Form1
引用了Class1
(通过MyClass1
变量),Class1
包含了一个通过theForm
变量对表单对象的引用。这导致了参考循环。终止处理程序不会触发,因为该类从未终止,它会无限期地保留在内存中,并且关闭并重新打开该表单只是打开了该类的新实例。
第二个版本引起了一个问题:当引用循环中断时,对Form1
的引用首先被释放(因为Class1
上仍然有对Form1
的引用),导致垃圾收集器进行清理,然后释放对Class1
的引用,垃圾收集器尝试清理Class1
,包括文本框对象SomeTextbox
,导致自表单以来就发生了硬崩溃对象已被清理,文本框对象无效。
解决方案是通过首先删除对Class1
的所有引用来打破引用循环。这不会导致崩溃。
Private Sub Form_Unload(Cancel As Integer)
Set myClass1 = Nothing
End Sub
这将导致垃圾收集器首先清除Class1实例,释放对Text0的引用,然后清除表单对象,因为没有人对此有开放的引用。