经测试发现如下情况:
一个例子项目里面有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)来判断无法避免这个问题。
各位有何高招?

解决方案 »

  1.   

    用forms集合,然后判断那个是B,然后unload
      

  2.   

    if not (B is nothing) then ...
      

  3.   

    我的意思不是找不到B,而是如果B还没有实例化的时候或者已经释放过一次之后,如何避免再一次的释放,因为再一次调用B时会对B实例化,sxfzu(Flying)提到的方法就对B进行了实例化(和IsObject()的结果一样),导致B产生了,而且这种形式产生的B必须Show出来之后才能释放他的资源。rexyudl(隼)的意思难道是说,对所有可能的操作流程都去人工的定制释放函数?如果一个项目有多个出口,每个出口处可能的需要释放的窗体数目都不同,你难道再每个出口都要写一批语句来释放资源,且不说代码重复,我想仅仅测试的工作量就不小了。
      

  4.   

    贴代码出来各位试试吧:
    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各位可以打开两千的任务管理器看看内存的使用情况。
      

  5.   

    Dim frm As Form
    For Each frm In Forms
        Unload frm
    Next
      

  6.   

    easy ba?:if not (frmB is nothing) then
        
      

  7.   

    再次强调:如果frmB还未分配内存时,调用“frmB is nothing”将导致frmB的内存分配动作,而且这种分配调用Unload frmB;Set frmB = nothing是没有用的! cslf(cs) 提到的方法实现机制我不是很明白,试试再说吧。
      

  8.   


    看来你提到的问题:“成批关闭窗体或者中途退出项目时,需要确保每个窗体都被释放”,关键问题是你在设计界面时采用什么方式使这些窗口出现,如果你采用show方法使之每次只有一个窗口出现,切换到其他窗体时使用set nothing ,然后unload,最后在退出整个程序时就没有必要frmB is nothing的调用。
    当然,如果程序必须工作在多窗口之下,这种方法不可行追求内存充分利用,vb有点麻烦
      

  9.   

    谁说frmB is nothing不行?
    你要把frmB当作一个对象来用
    加入你有一个窗体模块 frmPrint
    你就在公共模块里
    Public frmB as frmPrint
    然后就像类一样使用了
    但如果你连声明变量都想省掉的话那就不可能了 C++都帮不了你
      

  10.   

    unload 前先 load 
    :)损吧?!
      

  11.   

    Forms集合中存放到已加载的所有窗体,每个窗体都可以用一索引引用,如:Forms(0),用该集合来检查是否有窗体B不行吗?
      

  12.   

    呵呵,先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的时候,与资源分配没有任何关系!
      

  13.   

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

  14.   

    我还是这样认为:既然没有对frmB实例化,结束时就没有必要frmB nothing
      

  15.   

    我不明白 is Nothing 为什么会导致实例化呢?
      

  16.   

    我明白你的意思了
    1、因为你用了隐式实例化,所以Is Nothing也会导致实例化,但你用显示实例化就没有这回事了。因为你用隐式实例化时,vb会在你第一次引用对象变量的时候进行实例化。2、即使你使用隐式实例化,set * = nothing 仍然是有效,不信你可以在Form_Initialize()和Form_Terminate()设两个断点看看。这种事没必要小题大做。
      

  17.   

    呵呵,先回答几个简单问题先:
     lepeng(乐鹏):既然没有对frmB实例化,结束时就没有必要frmB nothing
    如果我确定frmB没有实例化,当然不必要frmB Nothing;
    问题是我怎么知道frmB没有实例化:一段代码一段代码的去读?每个frm产生实例化时产生一个变量标识它已经实例化了?第一种方法我认为是弱智,第二种方法烦琐而且生成新的变量浪费成本。至于Unload之前先Load问题也是增加了成本。其实这里的问题规到底,就是既要判断frmB是否被实例化了,还要避免在判断的时候实例化frmB!我相信一定有合适的办法的,这里有两种提议我还没有去测试是否有效:1、Forms集合中存放到已加载的所有窗体,每个窗体都可以用一索引引用,如:Forms(0),用该集合来检查是否有窗体B不行吗?
    点评:我不是VB高手,不清楚用集合检查是否有窗体B的过程,能贴段代码出来么?2、因为你用了隐式实例化,所以Is Nothing也会导致实例化,但你用显示实例化就没有这回事了。因为你用隐式实例化时,vb会在你第一次引用对象变量的时候进行实例化。
    点评:我还不确定显示实例化能否避免“第一次引用对象变量的时候进行实例化”或者“引用未实例化对象变量的时候进行实例化”,因为还没有空去测试
      

  18.   

    关于 Greaitm(夜草) 提到的这种事情没必要小题大做嘛,看看这么多人回帖都没有给出明确的答案来我就认为有必要!何况这个问题小么?我觉得它一点都不小,还很大:
    它关系到了窗体的生存期、资源的使用效率、VB语法的深层含义、软件的设计方法等等……
    而且我想除了窗体的使用是这样,VB里的类也会有这种问题。最后发点牢骚吧:各位跟贴的朋友都有没有把自己提出来的方法去试一下?如果你很忙,仅仅提出一个意见我可以理解,不过会有这么多人都很忙么?!
      

  19.   

    既然你没有测试过就不要说已经事例化了,我没有告诉你怎么测吗?你看得不认真而已。
    就是用显式事例化:
    做两个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 会导致实例化。
    老实说,每次回你的贴我都很认真,做过测试才说的,我之前回了三次贴,你一个一个的看
    按我说的,怎么会不行呢?
      

  20.   

    Greaitm(夜草)很感谢你带给我的帮助!
    前面提到的“各位跟贴的朋友都有没有把自己提出来的方法去试一下”是偏激了一点,请你见谅!你提到的先声明的方法是对的,之前一段时间都比较忙,加上自己一懒惰就一直没有去测试。之前提到的“显示实例化”是我对VB的理解错误,VB里很多变量在定义时就做了内存分配动作,而窗体、类、数组的内存分配实际上都和new、ReDim等关联在一起。关于隐式实例化真的让我头疼,我测试了Unload FrmB(之前FrmB未定义未实例化),发现发生了内存分配,然后再调用Unload FrmB内存并没有释放,而且我在FrmB的Form_Unload里调用了Set FrmB = Nothing语句,所以错误的认为隐式实例化即使使用Set FrmB = Nothing也不能释放,实际上第二次调用Unload FrmB时根本就不会调用From_Unload
      

  21.   

    先建立一个数组,最好大一点的,一个公用变量
    没显示一个窗口,就:
    set myobject(i)=myform
    i=i+1
    然后退出的时候
    for j=0 to i
    unload myobject(i)
    next
      

  22.   

    哦,你是工程监理。这个工作,应由coder给说明撒……累啊最后还是回到一行一行的code上了谢你的分:)