废话少说,看代码:测试工程1:
------------------------
类ct代码
------------------------Option Explicit
Private m_lngV2 As Long
Private m_lngV1 As Long
Private m_lngV3 As Long
Private m_lngV4 As Long
Private m_lngV5 As Long
Private m_lngV6 As Long
Private m_lngV7 As Long
Private m_lngV8 As Long
Private m_lngV9 As LongPublic Property Get V9() As Long
V9 = m_lngV9
End PropertyPublic Property Let V9(ByVal lngValue As Long)
m_lngV9 = lngValue
End PropertyPublic Property Get V8() As Long
V8 = m_lngV8
End PropertyPublic Property Let V8(ByVal lngValue As Long)
m_lngV8 = lngValue
End PropertyPublic Property Get V7() As Long
V7 = m_lngV7
End PropertyPublic Property Let V7(ByVal lngValue As Long)
m_lngV7 = lngValue
End PropertyPublic Property Get V6() As Long
V6 = m_lngV6
End PropertyPublic Property Let V6(ByVal lngValue As Long)
m_lngV6 = lngValue
End PropertyPublic Property Get V5() As Long
V5 = m_lngV5
End PropertyPublic Property Let V5(ByVal lngValue As Long)
m_lngV5 = lngValue
End PropertyPublic Property Get V4() As Long
V4 = m_lngV4
End PropertyPublic Property Let V4(ByVal lngValue As Long)
m_lngV4 = lngValue
End PropertyPublic Property Get V3() As Long
V3 = m_lngV3
End PropertyPublic Property Let V3(ByVal lngValue As Long)
m_lngV3 = lngValue
End PropertyPublic Property Get V1() As Long
V1 = m_lngV1
End PropertyPublic Property Let V1(ByVal lngValue As Long)
m_lngV1 = lngValue
End PropertyPublic Property Get V2() As Long
V2 = m_lngV2
End PropertyPublic Property Let V2(ByVal lngValue As Long)
m_lngV2 = lngValue
End PropertyPublic Sub SetValue(v() As Long)
m_lngV1 = v(0)
m_lngV2 = v(1)
m_lngV3 = v(2)
m_lngV4 = v(3)
m_lngV5 = v(4)
m_lngV6 = v(5)
m_lngV7 = v(6)
m_lngV8 = v(7)
m_lngV9 = v(8)
End Sub-----------------------
类cts代码
-----------------------
Option ExplicitPrivate m_Colcts As Collection
Private Sub Class_Initialize() Set m_Colcts = New CollectionEnd SubSub Add(CtItem As ct, Optional varKey As Variant) m_Colcts.Add CtItem, varKeyEnd SubSub Remove(varIndex As Variant) m_Colcts.Remove varIndexEnd SubFunction Item(varIndex As Variant) As ct Set Item = Nothing On Error Resume Next
Set Item = m_Colcts.Item(varIndex)
On Error GoTo 0End FunctionFunction Exists(varIndex As Variant) As Boolean Dim objTest As ct
Set objTest = Nothing If Count > 0 Then On Error Resume Next
Set objTest = Item(varIndex)
On Error GoTo 0 End If Exists = Not (objTest Is Nothing)End Function
Property Get Count() As Long Count = m_Colcts.CountEnd Property
Sub Clear() Set m_Colcts = New CollectionEnd SubFunction NewEnum() As IUnknown Set NewEnum = m_Colcts.[_NewEnum]End Function-----------------------
Form1代码
-----------------------
Option ExplicitPrivate ts As ctsPrivate Sub Command1_Click() Set ts = New cts Dim i As Long
Dim t As ct
Dim a(0 To 8) As Long For i = 0 To 8
a(i) = i
Next Me.Timer1.Enabled = True For i = 1 To 1000000
Set t = New ct
DoEvents
Me.Text1.Text = i
t.SetValue a
ts.Add t
Next Me.Timer1.Enabled = False
End SubPrivate Sub Form_QueryUnload(Cancel As Integer, UnloadMode As Integer)
Dim p As ct
For Each p In ts
DoEvents
Set p = Nothing
Next
Set ts = Nothing
End Sub------------------
注:
------------------
窗体Form1上放一个Command1,一个Text1-------------------
问题
-------------------
关闭程序时无响应,占用的一大块内存没有被释放。高手都来发表下意见吧……
------------------------
类ct代码
------------------------Option Explicit
Private m_lngV2 As Long
Private m_lngV1 As Long
Private m_lngV3 As Long
Private m_lngV4 As Long
Private m_lngV5 As Long
Private m_lngV6 As Long
Private m_lngV7 As Long
Private m_lngV8 As Long
Private m_lngV9 As LongPublic Property Get V9() As Long
V9 = m_lngV9
End PropertyPublic Property Let V9(ByVal lngValue As Long)
m_lngV9 = lngValue
End PropertyPublic Property Get V8() As Long
V8 = m_lngV8
End PropertyPublic Property Let V8(ByVal lngValue As Long)
m_lngV8 = lngValue
End PropertyPublic Property Get V7() As Long
V7 = m_lngV7
End PropertyPublic Property Let V7(ByVal lngValue As Long)
m_lngV7 = lngValue
End PropertyPublic Property Get V6() As Long
V6 = m_lngV6
End PropertyPublic Property Let V6(ByVal lngValue As Long)
m_lngV6 = lngValue
End PropertyPublic Property Get V5() As Long
V5 = m_lngV5
End PropertyPublic Property Let V5(ByVal lngValue As Long)
m_lngV5 = lngValue
End PropertyPublic Property Get V4() As Long
V4 = m_lngV4
End PropertyPublic Property Let V4(ByVal lngValue As Long)
m_lngV4 = lngValue
End PropertyPublic Property Get V3() As Long
V3 = m_lngV3
End PropertyPublic Property Let V3(ByVal lngValue As Long)
m_lngV3 = lngValue
End PropertyPublic Property Get V1() As Long
V1 = m_lngV1
End PropertyPublic Property Let V1(ByVal lngValue As Long)
m_lngV1 = lngValue
End PropertyPublic Property Get V2() As Long
V2 = m_lngV2
End PropertyPublic Property Let V2(ByVal lngValue As Long)
m_lngV2 = lngValue
End PropertyPublic Sub SetValue(v() As Long)
m_lngV1 = v(0)
m_lngV2 = v(1)
m_lngV3 = v(2)
m_lngV4 = v(3)
m_lngV5 = v(4)
m_lngV6 = v(5)
m_lngV7 = v(6)
m_lngV8 = v(7)
m_lngV9 = v(8)
End Sub-----------------------
类cts代码
-----------------------
Option ExplicitPrivate m_Colcts As Collection
Private Sub Class_Initialize() Set m_Colcts = New CollectionEnd SubSub Add(CtItem As ct, Optional varKey As Variant) m_Colcts.Add CtItem, varKeyEnd SubSub Remove(varIndex As Variant) m_Colcts.Remove varIndexEnd SubFunction Item(varIndex As Variant) As ct Set Item = Nothing On Error Resume Next
Set Item = m_Colcts.Item(varIndex)
On Error GoTo 0End FunctionFunction Exists(varIndex As Variant) As Boolean Dim objTest As ct
Set objTest = Nothing If Count > 0 Then On Error Resume Next
Set objTest = Item(varIndex)
On Error GoTo 0 End If Exists = Not (objTest Is Nothing)End Function
Property Get Count() As Long Count = m_Colcts.CountEnd Property
Sub Clear() Set m_Colcts = New CollectionEnd SubFunction NewEnum() As IUnknown Set NewEnum = m_Colcts.[_NewEnum]End Function-----------------------
Form1代码
-----------------------
Option ExplicitPrivate ts As ctsPrivate Sub Command1_Click() Set ts = New cts Dim i As Long
Dim t As ct
Dim a(0 To 8) As Long For i = 0 To 8
a(i) = i
Next Me.Timer1.Enabled = True For i = 1 To 1000000
Set t = New ct
DoEvents
Me.Text1.Text = i
t.SetValue a
ts.Add t
Next Me.Timer1.Enabled = False
End SubPrivate Sub Form_QueryUnload(Cancel As Integer, UnloadMode As Integer)
Dim p As ct
For Each p In ts
DoEvents
Set p = Nothing
Next
Set ts = Nothing
End Sub------------------
注:
------------------
窗体Form1上放一个Command1,一个Text1-------------------
问题
-------------------
关闭程序时无响应,占用的一大块内存没有被释放。高手都来发表下意见吧……
Set t = New ct
Private Sub Form_QueryUnload(Cancel As Integer, UnloadMode As Integer)
Dim i As Long
For i = ts.Count To 1 Step -1
ts.Remove i
Next
Set ts = Nothing
End Sub
Set ts = Nothing
End Sub盯着任务管理器,你会发现内存的确是被释放了,只不果释放速度比创建的时候慢
'释放内存,常用于第一次启动完窗体后,效果显著
Private Declare Function SetProcessWorkingSetSize Lib "kernel32" (ByVal hProcess As Long, ByVal dwMinimumWorkingSetSize As Long, ByVal dwMaximumWorkingSetSize As Long) As Long
Private Declare Function GetCurrentProcess Lib "kernel32" () As Long
Private Sub releasemem()
SetProcessWorkingSetSize GetCurrentProcess, -1, -1
End Sub
随着系统运行的时间越来越长,程序占用的内存越来越大,直至死机!你光靠VB自身释放恐怕是结局只有一个,那就是死机!用END语句程序会关掉的!fly1229的只是把当前应用程序进程占用的内存转至虚拟内存中,系统占用内存总数是不变的!之所以考虑到释放内存的问题,是因为程序要在服务器上运行,跑起来少则一个星期,VB的Nothing基本无用,尤其是对于大量对象的释放问题!
Dim i As Long
Dim sngStart As Single
Screen.MousePointer = vbHourglass
sngStart = Timer
For i = ts.Count To 1 Step -1
If i Mod 1000 = 0 Then
Debug.Print Timer - sngStart
DoEvents
sngStart = Timer
End If
ts.Remove i
Next
Set ts = Nothing
Debug.Print Timer - sngStart
Screen.MousePointer = vbDefault
End Sub
按照这个速度,100万个对象完全正常释放完毕约需5小时或更多!如果按照杯子的说法,exe要快些,假设快上5倍,那也需要1个小时!
这个只是用来测试的代码,目前就是占用了很大一块内存,该如何释放的问题。现实工程中肯定没有这样的代码,只不过我的工程中使用了一个很复杂的对象,实际运行时内存随着用户不停的操作而逐渐增加。程序中使用对象时,该SET NOTHING的地方全部都写了,检查了N遍了,问题依旧。
程序运行时SET NOTHING后,那一大块内存如何释放?关闭程序时直接TASKKILL 就OK了。
你说的很对,当创建完了,用完了,也SETNOTHING了,内存还是在,这才是问题!
类模块:4个
窗体:Form1,上面放一个Command1代码为:类CA:
------------------------------
Option ExplicitPrivate m_Childs As CBs
Private m_varIndexKey As StringPublic Property Get IndexKey() As String
IndexKey = m_varIndexKey
End PropertyPublic Property Let IndexKey(ByVal varValue As String)
m_varIndexKey = varValue
End PropertyPublic Property Get Childs() As CBs
Set Childs = m_Childs
End PropertyPrivate Sub Class_Initialize()
Set m_Childs = New CBs
Set m_Childs.Category = Me
End SubPrivate Sub Class_Terminate()
Set m_Childs = Nothing
End Sub类CAs:
---------------------------------------
Option Explicit
Private m_ColCAs As Collection
Private Sub Class_Initialize()
Set m_ColCAs = New Collection
End SubSub Add(CAItem As CA, Optional varKey As Variant)
If IsMissing(varKey) Then
m_ColCAs.Add CAItem, CAItem.IndexKey
Else
m_ColCAs.Add CAItem, varKey
End If
End Sub
Sub Remove(varIndex As Variant)
m_ColCAs.Remove varIndex
End Sub
Function Item(varIndex As Variant) As CA Set Item = Nothing On Error Resume Next
Set Item = m_ColCAs.Item(varIndex)
On Error GoTo 0End Function
Function Exists(varIndex As Variant) As Boolean Dim objTest As CA
Set objTest = Nothing If Count > 0 Then On Error Resume Next
Set objTest = Item(varIndex)
On Error GoTo 0 End If Exists = Not (objTest Is Nothing)End Function
Property Get Count() As Long Count = m_ColCAs.CountEnd PropertySub Clear() Set m_ColCAs = New CollectionEnd Sub
Function NewEnum() As IUnknown Set NewEnum = m_ColCAs.[_NewEnum]End FunctionPrivate Sub Class_Terminate()
Set m_ColCAs = Nothing
End Sub类CB:
--------------------------------------
Option ExplicitPrivate m_Parent As CA
Private m_varIndexKey As StringPublic Property Get IndexKey() As String
IndexKey = m_varIndexKey
End PropertyPublic Property Let IndexKey(ByVal varValue As String)
m_varIndexKey = varValue
End PropertyPublic Property Get Parent() As CA
Set Parent = m_Parent
End PropertyPublic Property Set Parent(ByVal CAValue As CA)
Set m_Parent = CAValue
End PropertyPrivate Sub Class_Terminate()
Set m_Parent = Nothing
End Sub类CBs:
---------------------------------------------------
Option Explicit
Private m_ColCBs As Collection
Private m_Category As CAPublic Property Set Category(ByVal CAValue As CA)
Set m_Category = CAValue
End Property
Private Sub Class_Initialize()
Set m_ColCBs = New Collection
End SubSub Add(CBItem As CB, Optional varKey As Variant)
Set CBItem.Parent = m_Category
If IsMissing(varKey) Then
m_ColCBs.Add CBItem, CBItem.IndexKey
Else
m_ColCBs.Add CBItem, varKey
End If
End Sub
Sub Remove(varIndex As Variant)
m_ColCBs.Remove varIndex
End Sub
Function Item(varIndex As Variant) As CB Set Item = Nothing On Error Resume Next
Set Item = m_ColCBs.Item(varIndex)
On Error GoTo 0End Function
Function Exists(varIndex As Variant) As Boolean Dim objTest As CB
Set objTest = Nothing If Count > 0 Then On Error Resume Next
Set objTest = Item(varIndex)
On Error GoTo 0 End If Exists = Not (objTest Is Nothing)End Function
Property Get Count() As Long
Count = m_ColCBs.Count
End Property
Sub Clear()
Set m_ColCBs = New Collection
End Sub
Function NewEnum() As IUnknown
Set NewEnum = m_ColCBs.[_NewEnum]
End FunctionPrivate Sub Class_Terminate()
Set m_ColCBs = Nothing
Set m_Category = Nothing
End Sub窗体Form1:
-------------------------------------
Option ExplicitPrivate Sub Command1_Click()
Me.Command1.Enabled = False
Dim tCas As CAs
Set tCas = New CAs
Dim tCa As CA
Dim iCa As Integer
For iCa = 1 To 50
Set tCa = New CA
tCa.IndexKey = "a" & iCa
Dim tCb As CB
Dim iCb As Long
For iCb = 1 To 50
Set tCb = New CB
tCb.IndexKey = "b" & iCb
tCa.Childs.Add tCb
Set tCb = Nothing
Next
tCas.Add tCa
Set tCa = Nothing
Next
'做要做的事
Debug.Print tCas.Count, tCas.Item(1).Childs.Count
'做完了释放
Set tCas = Nothing
Me.Command1.Enabled = True
End Sub编译为EXE后:
你点按钮Command1,内存也是越来越大,随着你点的次数不断增多,最终也会死机。先生们,女士们,类得撕俺的街头门,帮忙分析一下是什么原因造成的内存不断上涨呢???
楼主的类对象 这里 Set m_Childs ,那里 Set m_Parent ,造成对象之间的循环引用。
最终的后果就是:对象在运行期间无法被释放!
所以,运行时,内存占用越来越多。
楼主试一下下面的这段代码(按 32F 的窗体代码修改的,类代码没动),无论你点多少次按钮,开始时内存会增加(通过任务管理器来看的),但增加一定的数量后就不再增涨了(增加量不算多)。
但是,如果没有我添加的那几句代码,就会内存占用‘无限增涨’(也许是,我不可能让我的系统 GAME OVER)。
Private Sub Command1_Click()
Me.Command1.Enabled = False
Dim tCas As CAs
Set tCas = New CAs
Dim tCa As CA
Dim iCa As Integer
For iCa = 1 To 100 '我改到 100 了。
Set tCa = New CA
tCa.IndexKey = "a" & iCa
Dim tCb As CB
Dim iCb As Long
For iCb = 1 To 50
Set tCb = New CB
tCb.IndexKey = "b" & iCb
tCa.Childs.Add tCb
Set tCb = Nothing
Next
tCas.Add tCa
Set tCa = Nothing
Next
'做要做的事
Debug.Print tCas.Count, tCas.Item(1).Childs.Count
'做完了释放
' ****** 楼主注意比较有这段代码和没这段代码的区别 ******
Dim i&, k&
For i = tCas.Count To 1 Step -1
For k = tCas.Item(i).Childs.Count To 1 Step -1
tCas.Item(i).Childs.Remove tCas.Item(i).Childs.Item(1).IndexKey
Next
Set tCas.Item(i).Childs.Category = Nothing
tCas.Remove tCas.Item(i).IndexKey
Next
' *******************************************************
Set tCas = Nothing
Me.Command1.Enabled = True
End Sub
我用22楼办法释放的,也没用。
cts是个典型的集合类,通常都是那样做的,我看不出有什么问题。
只要在代码中有个:Set ts = Nothing
或者 重新 New 一个 cts 给 ts。就可以让原来 New 的 ct 对象释放。你在 22F 的代码,似乎没有必要。还不如让程序自己完成释放操作。
(刚发现楼主 0F 的 Form_QueryUnload() 事件代码是错误的)
编译成 exe 文件后,每秒钟大概可以释放 7W 个 ct对象(xixi 怎么1000个要1、2分钟?),100W 要十几秒时间。
按楼主 0F 的代码(修正错误后),关闭程序时,窗口立即消失,但进程需要一段时间才销毁。
楼主说的“关闭程序时无响应,占用的一大块内存没有被释放。”应该是不存在的现象。
m_Colcts对象 的 .Remove 在对象很多的时候很耗时。
如果有的话记住在对象使用完成以后 erase一下,否则即使set nothing了内存也不会释放的
显示工程的类结构非常庞大,运行时最多同时存在的也就20个左右(因为在服务器运行,连接数约为20个),0楼发的是模拟占用内存块的测试程序,没有人会在程序里傻不拉基的在FOR循环中New了那么多对象又释放。测试工程为了演示说明如何释放比较大的内存块。所以你在这里说工程与现实如何如何没有任何意义。虽然说的没有意思,还是感谢你的热心参与!
Set obj=Nothing
在客户端请求对象时,每个对象将创建在一个新的线程上。当最终客户端释放对某线程上的对象的最后一个引用后,该线程就终止。请注意,客户端可能会引用一个线程上的几个对象。假设客户端创建了一个 Widget 对象,该对象又依次创建了两个从属对象 Sprocket 和 Gear。如果客户端得到对 Sprocket 对象的引用后释放了该 Widget 对象,该线程仍将存在,直至 Sprocket 对象被释放。在这种方式下,如果保留了不被使用的线程,最终会导致系统性能下降。因此,在使用多线程部件时,避免对象引用悬空是十分关键的。
'以下是Form中的改进后的部分
Option ExplicitPrivate ts As ctsPrivate Sub Command1_Click() Set ts = New cts Dim i As Long
Dim t As ct
Dim a(0 To 8) As Long
Dim TimeLog As Double
TimeLog = Timer For i = 0 To 8
a(i) = i
Next Me.Timer1.Enabled = True
Set t = New ct
t.SetValue a For i = 1 To 1000000
ts.Add t Next
Me.Text1.Text = i - 1 & "OK"
Set t = Nothing Me.Timer1.Enabled = False
Debug.Print Timer - TimeLog
End SubPrivate Sub Form_QueryUnload(Cancel As Integer, UnloadMode As Integer)
' Dim p As ct
' For Each p In ts
'
' ' DoEvents
'
' Set p = Nothing
'
' Next
'
' Set ts = Nothing Set ts = Nothing
End Sub
测试的结果: .87518750000163
.781562500000291
.907062500002212
.782312499999534
.78143750000163