您的位置:首页 > 编程语言 > VB

vb.net下如何销毁类的实例

2009-11-17 13:56 375 查看
原提问地址:http://hi.csdn.net/link.php?url=http://topic.csdn.net%2Fu%2F20091116%2F22%2F67d13f8b-3f05-4455-8042-721f5198b1b5.html

vb.net下如何销毁类的实例,这个问题其实已经困扰了我至少两年之久,一直没有时间来做个实验,于是在简单做了个实验后,发帖于CSDN。(请原谅我的命名规则,切勿模仿!)

实验的过程非常简单,创建一个名为class1的类,类中只有一个字符串变量及一个timer,用于控制输出的内容及间隔,在form1的load 过程中,创建一个class1的实例,在 button1 的click事件中创建class1的另一个实例,并将第一个实例销毁;

代码如下:

Public Class Form1
Public bb As New SortedList
Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
Dim class1 As New Class1("第1个类的实例")
bb.Add(bb.Count, class1)
End Sub

Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
Dim class1 As New Class1("第2个类的实例")
'********
bb.Add(bb.Count, class1)
End Sub
End Clas


Public Class Class1
Public aa As String
Public WithEvents t As New Timer
Sub New(ByVal value As String)
aa = value
t.Interval = 1000
t.Start()
End Sub
Private Sub t_Tick(ByVal sender As Object, ByVal e As System.EventArgs) Handles t.Tick
Debug.WriteLine(Now.ToString & "---->" & aa)
End Sub
End Class


先后创建的两个实例的变量,均是过程级的,按十年前的学习教程讲到的“生存周期”,我理解的过程级变量在过程结束后自动销毁,但是,当form1的load 过程结束后,我仍然能看到"xxxx/xx/xx xx:xx:xx-->第1个类的实例"以一秒的间隔被DEBUG出来,也就是说,过程是结束了,(也许变量已经被销毁了)但是该实例并没有被销毁,由此,我可以得到变量与实例并不是一回事,通俗的讲,此处的变量,只是这个实例的一个名字或者说别名罢了(至少在过程中,可以通过这个名字找到这个实例)。

我的目的是在第二个实例创建的时候,销毁第一个实例,但是由于第一个实例的变量是过程级的,在button1 的click事件中我无法索引到它,因此无法将其销毁,所以,在创建第一个实例的时候,我将它加入一个集合中,button1 的click事件中我有一行“******”的代码,其实我是尝试了如下几种方法:

方法一:

Dim t As Class1 = bb.Item(0)
t.Dispose()


方法二:

Dim t As Class1 = bb.Item(0)
t=nothing


方法三:

bb.remove(0)


甚至将上述三种方法组合使用,我仍然能看到讨厌的"xxxx/xx/xx xx:xx:xx-->第1个类的实例"以一秒的间隔被DEBUG出来,尽管bb这个集合中已经没有该对象了,尽管t已经被置为nothing了!

在方法一的应用时,我根据CSDN坛里兄弟及几个朋友的建议,将class1继续了IDisposable接口,代码如下:

Public Class Class1
Implements IDisposable
Protected disposed As Boolean = False
Public aa As String
Public WithEvents t As New Timer

Sub New(ByVal value As String)
aa = value
t.Interval = 1000
t.Start()
End Sub
Private Sub t_Tick(ByVal sender As Object, ByVal e As System.EventArgs) Handles t.Tick
Debug.WriteLine(Now.ToString & "---->" & aa)
End Sub

Protected Overridable Overloads Sub Dispose( _
ByVal disposing As Boolean)
If Not Me.disposed Then
If disposing Then
't.Dispose()  '时钟对象是销毁了,但是这个类的实例也同时销毁了吗?
End If
End If
Me.disposed = True
End Sub

Public Sub AnyOtherMethods()
If Me.disposed Then
Throw New ObjectDisposedException(Me.GetType().ToString, "This object has been disposed.")
End If
End Sub

#Region " IDisposable Support "
Public Overloads Sub Dispose() Implements IDisposable.Dispose
Dispose(True)
GC.SuppressFinalize(Me)
End Sub
Protected Overrides Sub Finalize()
Dispose(False)
MyBase.Finalize()
End Sub
#End Region
End Class


只有我在Dispose方法中,将t也Dispose的时候,讨厌的的提示才没有,但是,又如我在t.Dispose后边的注释写的一样,新的问题出现了,时钟对象是销毁了,但是这个类的实例也同时销毁了吗?
为了验证类的实例是否真的被销毁了,我将class1进行了一个小的改造,在其初始化的时候,开一个100MB大小的 byte数组,变动后的代码如下:

Public Class Class1
Implements IDisposable
Protected disposed As Boolean = False
Public aa As String
Public WithEvents t As New Timer
Public b0(102400000) As Byte

Sub New(ByVal value As String)
aa = value
t.Interval = 1000
t.Start()

For i = 0 To 102400000 - 1
b0(i) = &HFF
Next

End Sub
Private Sub t_Tick(ByVal sender As Object, ByVal e As System.EventArgs) Handles t.Tick
Debug.WriteLine(Now.ToString & "---->" & aa)
End Sub

Protected Overridable Overloads Sub Dispose( _
ByVal disposing As Boolean)
If Not Me.disposed Then
If disposing Then
t.Dispose()  '时钟对象是销毁了,但是这个类的实例也同时销毁了吗?
End If
End If
Me.disposed = True
End Sub

Public Sub AnyOtherMethods()
If Me.disposed Then
Throw New ObjectDisposedException(Me.GetType().ToString, "This object has been disposed.")
End If
End Sub

#Region " IDisposable Support "
Public Overloads Sub Dispose() Implements IDisposable.Dispose
Dispose(True)
GC.SuppressFinalize(Me)
End Sub
Protected Overrides Sub Finalize()
Dispose(False)
MyBase.Finalize()
End Sub
#End Region
End Class


如我想像,当窗体加载时,我发现该应用程序占去了100多MB的内存空间,当button1被按下后,第1个类实例的文字确实没有了,但是,同时内存空间双多了100MB(因为实例了第二个),也就是说,时钟对象是销毁了,但是这个类的实例却没有被销毁!

考虑到有朋友认为,垃圾回收是系统自动完成的,且,当该类没有任何实例的时候,系统会自动回收,那么,就可以理解成,当类仍然存在实例的时候,其它实例的资源系统是不回收的,这显然不满足实际的开发需要。我的实际工作是要管理上万个tcp的联接,每个终端对象都会频繁的联接、断开,周而复始,一个对象断开后,我就要释放相应的资源,否则,经过N多次的断开联接后,可能只保持一个联接里,我的系统资源已经没有了(因为类仍然有实例,资源没有被自动回收)。

于是,在创建第二个实例的时候,我强制要求系统回收资源,button1 的click事件变更成:

Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
Dim class1 As New Class1("第2个类的实例")
Dim t As Class1 = bb.Item(0) t.Dispose()t = Nothing
bb.Remove(0)
System.GC.Collect()
System.GC.WaitForPendingFinalizers()
bb.Add(bb.Count, class1)
End Sub


重新实验,当button1被按下后,第1个类实例的文字没有了,第2个类的实例开始按1秒的间隔被Debug出来,内存的开销只增加了几K,实例1被销毁了。

总结:

有朋友说,集合中记录的只是个引用,不能记录在集合中,对象的存储和调用本身就是按址引用的,所以,这个不存在问题;

我测试开了100M的byte数组有些bt,但足以说明问题,我们不能因为现在内存及CPU足够大,足够快而忽视对资源的掌握;

.Net 的垃圾回收并不是万能的;

实验很重要。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: