经测试发现如下情况:
一个例子项目里面有A、B两个窗体,A为启动窗体,在未对B进行任何有意义的操作之前(Load、Show等),如果调用了Unload B,B窗体将在内存中瓜分内存,而且这种情况即使使用Unload B(B_Unload中调用Set B = nothing)都无法释放B,只能在Show B后再调用Unload函数才可以释放B;提出此问题的意义:
在多窗体项目中,如果单个单个窗体退出时很容易正确释放窗体占用的资源,而成批关闭窗体或者中途退出项目时,需要确保每个窗体都被释放,如果这个时候调用Unload函数操作了一个已经释放过内存的或者未Load过的窗体,将会有资源泄漏。使用IsObject(B)来判断无法避免这个问题。
各位有何高招?
一个例子项目里面有A、B两个窗体,A为启动窗体,在未对B进行任何有意义的操作之前(Load、Show等),如果调用了Unload B,B窗体将在内存中瓜分内存,而且这种情况即使使用Unload B(B_Unload中调用Set B = nothing)都无法释放B,只能在Show B后再调用Unload函数才可以释放B;提出此问题的意义:
在多窗体项目中,如果单个单个窗体退出时很容易正确释放窗体占用的资源,而成批关闭窗体或者中途退出项目时,需要确保每个窗体都被释放,如果这个时候调用Unload函数操作了一个已经释放过内存的或者未Load过的窗体,将会有资源泄漏。使用IsObject(B)来判断无法避免这个问题。
各位有何高招?
Form1:
Option ExplicitPrivate lzData(10000000) As Long
Private ni As Integer
Public nj As IntegerPrivate Sub LoadFrm1_Click()
Load Form2
End SubPrivate Sub ShowFrm2_Click()
Dim lzData2(10000000) As LongForm2.Show
End Sub
Private Sub UnloadFrm2_Click()
If Not (Form2 Is Nothing) Then
Unload Form2
End If
End SubPrivate Sub Form_Unload(Cancel As Integer)
If Not (Form2 Is Nothing) Then Unload Form2
Unload Me
Set Form1 = Nothing
End SubForm2:
Option Explicit
Dim lzData3(20000000) As LongPrivate Sub UnloadMe_Click()
Unload Me
End SubPrivate Sub SetNothing_Click()
Set Form2 = Nothing
End SubPrivate Sub Form_Load()
Text1.Text = Form1.nj
Text2.Text = Form1.njEnd Sub
Private Sub Form_Unload(Cancel As Integer)
Unload Me
Set Form2 = Nothing
End Sub各位可以打开两千的任务管理器看看内存的使用情况。
For Each frm In Forms
Unload frm
Next
看来你提到的问题:“成批关闭窗体或者中途退出项目时,需要确保每个窗体都被释放”,关键问题是你在设计界面时采用什么方式使这些窗口出现,如果你采用show方法使之每次只有一个窗口出现,切换到其他窗体时使用set nothing ,然后unload,最后在退出整个程序时就没有必要frmB is nothing的调用。
当然,如果程序必须工作在多窗口之下,这种方法不可行追求内存充分利用,vb有点麻烦
你要把frmB当作一个对象来用
加入你有一个窗体模块 frmPrint
你就在公共模块里
Public frmB as frmPrint
然后就像类一样使用了
但如果你连声明变量都想省掉的话那就不可能了 C++都帮不了你
:)损吧?!
如果用C++来做类似的事情,那就太简单了:
FrmB* pB = NULL;
...
if (pB != NULL) delete pB; //或者直接:delete pB
这样不会有任何副作用,因为你使用pB的时候,与资源分配没有任何关系!
当然,如果对象已经存在时,Load操作什么也不做,没有什么浪费。
1、因为你用了隐式实例化,所以Is Nothing也会导致实例化,但你用显示实例化就没有这回事了。因为你用隐式实例化时,vb会在你第一次引用对象变量的时候进行实例化。2、即使你使用隐式实例化,set * = nothing 仍然是有效,不信你可以在Form_Initialize()和Form_Terminate()设两个断点看看。这种事没必要小题大做。
lepeng(乐鹏):既然没有对frmB实例化,结束时就没有必要frmB nothing
如果我确定frmB没有实例化,当然不必要frmB Nothing;
问题是我怎么知道frmB没有实例化:一段代码一段代码的去读?每个frm产生实例化时产生一个变量标识它已经实例化了?第一种方法我认为是弱智,第二种方法烦琐而且生成新的变量浪费成本。至于Unload之前先Load问题也是增加了成本。其实这里的问题规到底,就是既要判断frmB是否被实例化了,还要避免在判断的时候实例化frmB!我相信一定有合适的办法的,这里有两种提议我还没有去测试是否有效:1、Forms集合中存放到已加载的所有窗体,每个窗体都可以用一索引引用,如:Forms(0),用该集合来检查是否有窗体B不行吗?
点评:我不是VB高手,不清楚用集合检查是否有窗体B的过程,能贴段代码出来么?2、因为你用了隐式实例化,所以Is Nothing也会导致实例化,但你用显示实例化就没有这回事了。因为你用隐式实例化时,vb会在你第一次引用对象变量的时候进行实例化。
点评:我还不确定显示实例化能否避免“第一次引用对象变量的时候进行实例化”或者“引用未实例化对象变量的时候进行实例化”,因为还没有空去测试
它关系到了窗体的生存期、资源的使用效率、VB语法的深层含义、软件的设计方法等等……
而且我想除了窗体的使用是这样,VB里的类也会有这种问题。最后发点牢骚吧:各位跟贴的朋友都有没有把自己提出来的方法去试一下?如果你很忙,仅仅提出一个意见我可以理解,不过会有这么多人都很忙么?!
就是用显式事例化:
做两个Form
Form1:
Private frm2 as Form2
Private sub Form_Load()
debug.print frm2 is nothing
end subForm2:
在以下两个函数设断点:
private sub Form_Initialize()
'该事件在事例化时调用
end sub
private sub Form_Terminate()
'该事件在清理对象时调用
end sub通过这个测试你就知道 Is Nothing时没有实例化
等你要实例化时,你用Set frm2=new Form2
就可以了。
做这个小例子不用10秒钟。这问题别人没有回答正确,是因为你一开始就强调Is nothing 会导致实例化。
老实说,每次回你的贴我都很认真,做过测试才说的,我之前回了三次贴,你一个一个的看
按我说的,怎么会不行呢?
前面提到的“各位跟贴的朋友都有没有把自己提出来的方法去试一下”是偏激了一点,请你见谅!你提到的先声明的方法是对的,之前一段时间都比较忙,加上自己一懒惰就一直没有去测试。之前提到的“显示实例化”是我对VB的理解错误,VB里很多变量在定义时就做了内存分配动作,而窗体、类、数组的内存分配实际上都和new、ReDim等关联在一起。关于隐式实例化真的让我头疼,我测试了Unload FrmB(之前FrmB未定义未实例化),发现发生了内存分配,然后再调用Unload FrmB内存并没有释放,而且我在FrmB的Form_Unload里调用了Set FrmB = Nothing语句,所以错误的认为隐式实例化即使使用Set FrmB = Nothing也不能释放,实际上第二次调用Unload FrmB时根本就不会调用From_Unload
没显示一个窗口,就:
set myobject(i)=myform
i=i+1
然后退出的时候
for j=0 to i
unload myobject(i)
next