求教:如何防止Unload一个未Load过的窗体?

Rainee 2003-12-22 03:12:45
经测试发现如下情况:
一个例子项目里面有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)来判断无法避免这个问题。
各位有何高招?
...全文
25 点赞 收藏 27
写回复
27 条回复
切换为时间正序
当前发帖距今超过3年,不再开放新的回复
发表回复
lepeng 2004-01-03
哦,你是工程监理。

这个工作,应由coder给说明撒……

累啊

最后还是回到一行一行的code上了

谢你的分:)
回复
mmcgzs 2003-12-31
先建立一个数组,最好大一点的,一个公用变量
没显示一个窗口,就:
set myobject(i)=myform
i=i+1
然后退出的时候
for j=0 to i
unload myobject(i)
next
回复
Rainee 2003-12-31
转了一大圈后,我想结论就是:

“使用窗体应该像使用类一样明确的声明它。”

否则就很有可能造成内存的浪费和泄漏,尤其是对多窗体的项目。
再次感谢各位的支持与指导,恭祝大家新年愉快!
回复
Rainee 2003-12-31
Greaitm(夜草)

很感谢你带给我的帮助!
前面提到的“各位跟贴的朋友都有没有把自己提出来的方法去试一下”是偏激了一点,请你见谅!

你提到的先声明的方法是对的,之前一段时间都比较忙,加上自己一懒惰就一直没有去测试。之前提到的“显示实例化”是我对VB的理解错误,VB里很多变量在定义时就做了内存分配动作,而窗体、类、数组的内存分配实际上都和new、ReDim等关联在一起。

关于隐式实例化真的让我头疼,我测试了Unload FrmB(之前FrmB未定义未实例化),发现发生了内存分配,然后再调用Unload FrmB内存并没有释放,而且我在FrmB的Form_Unload里调用了Set FrmB = Nothing语句,所以错误的认为隐式实例化即使使用Set FrmB = Nothing也不能释放,实际上第二次调用Unload FrmB时根本就不会调用From_Unload

回复
Greaitm 2003-12-30
既然你没有测试过就不要说已经事例化了,我没有告诉你怎么测吗?你看得不认真而已。
就是用显式事例化:
做两个Form
Form1:
Private frm2 as Form2
Private sub Form_Load()
debug.print frm2 is nothing
end sub

Form2:
在以下两个函数设断点:
private sub Form_Initialize()
'该事件在事例化时调用
end sub
private sub Form_Terminate()
'该事件在清理对象时调用
end sub

通过这个测试你就知道 Is Nothing时没有实例化
等你要实例化时,你用Set frm2=new Form2
就可以了。
做这个小例子不用10秒钟。

这问题别人没有回答正确,是因为你一开始就强调Is nothing 会导致实例化。
老实说,每次回你的贴我都很认真,做过测试才说的,我之前回了三次贴,你一个一个的看
按我说的,怎么会不行呢?
回复
Rainee 2003-12-25
关于 Greaitm(夜草) 提到的这种事情没必要小题大做嘛,看看这么多人回帖都没有给出明确的答案来我就认为有必要!

何况这个问题小么?我觉得它一点都不小,还很大:
它关系到了窗体的生存期、资源的使用效率、VB语法的深层含义、软件的设计方法等等……
而且我想除了窗体的使用是这样,VB里的类也会有这种问题。

最后发点牢骚吧:各位跟贴的朋友都有没有把自己提出来的方法去试一下?如果你很忙,仅仅提出一个意见我可以理解,不过会有这么多人都很忙么?!
回复
Rainee 2003-12-25
呵呵,先回答几个简单问题先:
lepeng(乐鹏):既然没有对frmB实例化,结束时就没有必要frmB nothing
如果我确定frmB没有实例化,当然不必要frmB Nothing;
问题是我怎么知道frmB没有实例化:一段代码一段代码的去读?每个frm产生实例化时产生一个变量标识它已经实例化了?第一种方法我认为是弱智,第二种方法烦琐而且生成新的变量浪费成本。至于Unload之前先Load问题也是增加了成本。

其实这里的问题规到底,就是既要判断frmB是否被实例化了,还要避免在判断的时候实例化frmB!我相信一定有合适的办法的,这里有两种提议我还没有去测试是否有效:

1、Forms集合中存放到已加载的所有窗体,每个窗体都可以用一索引引用,如:Forms(0),用该集合来检查是否有窗体B不行吗?
点评:我不是VB高手,不清楚用集合检查是否有窗体B的过程,能贴段代码出来么?

2、因为你用了隐式实例化,所以Is Nothing也会导致实例化,但你用显示实例化就没有这回事了。因为你用隐式实例化时,vb会在你第一次引用对象变量的时候进行实例化。
点评:我还不确定显示实例化能否避免“第一次引用对象变量的时候进行实例化”或者“引用未实例化对象变量的时候进行实例化”,因为还没有空去测试

回复
FSoft 2003-12-24
Forms集合中存放到已加载的所有窗体,每个窗体都可以用一索引引用,如:Forms(0),用该集合来检查是否有窗体B不行吗?
回复
lepeng 2003-12-24
我还是这样认为:既然没有对frmB实例化,结束时就没有必要frmB nothing
回复
Rainee 2003-12-24
不过我觉得即使使用Load先,也还是有个问题:

就是每次试图释放一个不存在的对象时,都先产生这个对象,成本太高了!各位还有没有其他的高招?
当然,如果对象已经存在时,Load操作什么也不做,没有什么浪费。

回复
Rainee 2003-12-24
呵呵,先Load一下是高招,谢啦!

Greaitm(夜草)提到的窗体使用前先声明也是个不错的习惯,不过即使声明了,也要考虑实例化吧。前面提到Set nothing不行主要意思是说:FrmB未实例化以前或者说已经释放了以后,如果再调用类似Isobject(FrmB)、FrmB is nothing、unload FrmB等语句中的任何一句语句,都会导致FrmB的实例化,请注意,即使是Unload FrmB都是导致FrmB实例化,就是说你执行FrmB后内存中FrmB从无变有了,而Unload的作用就是把有变为无,彻底的反逻辑了!
如果用C++来做类似的事情,那就太简单了:
FrmB* pB = NULL;
...
if (pB != NULL) delete pB; //或者直接:delete pB
这样不会有任何副作用,因为你使用pB的时候,与资源分配没有任何关系!
回复
kmzs 2003-12-24
先Load吧,或都Load一下
回复
Greaitm 2003-12-24
我明白你的意思了
1、因为你用了隐式实例化,所以Is Nothing也会导致实例化,但你用显示实例化就没有这回事了。因为你用隐式实例化时,vb会在你第一次引用对象变量的时候进行实例化。

2、即使你使用隐式实例化,set * = nothing 仍然是有效,不信你可以在Form_Initialize()和Form_Terminate()设两个断点看看。

这种事没必要小题大做。
回复
Greaitm 2003-12-24
我不明白 is Nothing 为什么会导致实例化呢?
回复
rickytwice 2003-12-23
unload 前先 load
:)损吧?!
回复
summerhill 2003-12-23
easy ba?:

if not (frmB is nothing) then

回复
Greaitm 2003-12-23
谁说frmB is nothing不行?
你要把frmB当作一个对象来用
加入你有一个窗体模块 frmPrint
你就在公共模块里
Public frmB as frmPrint
然后就像类一样使用了
但如果你连声明变量都想省掉的话那就不可能了 C++都帮不了你
回复
liuyanghe111 2003-12-23
用一个变量始终跟踪B是否存在的状态应该可以
回复
cslf 2003-12-23
Dim frm As Form
For Each frm In Forms
Unload frm
Next
回复
Rainee 2003-12-23
贴代码出来各位试试吧:
Form1:
Option Explicit

Private lzData(10000000) As Long
Private ni As Integer
Public nj As Integer

Private Sub LoadFrm1_Click()
Load Form2
End Sub

Private Sub ShowFrm2_Click()
Dim lzData2(10000000) As Long

Form2.Show
End Sub


Private Sub UnloadFrm2_Click()
If Not (Form2 Is Nothing) Then
Unload Form2
End If
End Sub

Private Sub Form_Unload(Cancel As Integer)
If Not (Form2 Is Nothing) Then Unload Form2
Unload Me
Set Form1 = Nothing
End Sub

Form2:
Option Explicit
Dim lzData3(20000000) As Long

Private Sub UnloadMe_Click()
Unload Me
End Sub

Private Sub SetNothing_Click()
Set Form2 = Nothing
End Sub

Private Sub Form_Load()
Text1.Text = Form1.nj
Text2.Text = Form1.nj

End Sub


Private Sub Form_Unload(Cancel As Integer)
Unload Me
Set Form2 = Nothing
End Sub

各位可以打开两千的任务管理器看看内存的使用情况。
回复
发动态
发帖子
VB基础类
创建于2007-09-28

7453

社区成员

VB 基础类
申请成为版主
社区公告
暂无公告