如何查看在VB中实例化的对象哪些还在内存中占用着

时间:2022-05-02 09:23:19
    公司一个程序,经历了10年的开发历程,中间经手了不下6个程序员,由于代码书写没有按照规范:将实例化的对象用完后释放,导致现在程序长时间打开,在执行很多操作后,电脑报内存溢出,只能重开程序才能解决问题。
    怎么样才能监控出到底是那段代码的哪些对象没有被释放呢?现在都不知掉这么庞大的代码中哪些没有set 对象=nothing,寻求帮助。

20 个解决方案

#1


事实上,set x=nothing并不是必须的,VB在退出过程时会自动清理,你可以编写代码测试,你没有设nothing,但是Class_Terminate()是会执行(意味着自己清理)。关键是,你不能使用循环引用,如果存在循环引用,那你就需要设置nothing

#2


循环引用前好象会自动set nothing

#3


对啊,所以不少对象还有专门的Close,Dispose这类方法啊

#4


这个比较不现实,
除非你将每个对象的生成与销毁都保存下来,写入文件,否者难。

#5


   我现在是这个程序一直开在那边,自动的执行里面很多模块,现在很准时,2天必定WINDOW报out of memory,然后电脑就内存溢出了,只能将这个程序强行关闭,就好了,遇到这个情况我应该怎么去解决呢?

#6


补充一下,是VB执行的时候抛出的ERROR是 OUT OF MEMORY,此时远程连到这台电脑上,发现电脑就是内存溢出了,就像我们平时电脑程序开多了,点什么都没反应

#7


建议楼主仔细检查每个对象,看看有没有使用了没有释放的地方。此外你也可以把你怀疑的地方设置一些写标记语言,把每次用对象的地方都记入文件,以便出问题的时候查阅。

#8


按VB6标准的函数与语句来写的话,基本上是不会出现内存泄漏吧,除非使用了非VB6管理以外的东东,比如自己调用API申请内存内存,创建句柄之类,这些不是VB6的管理范围,得编码者自己把握.

#9


set nothing那玩意真的没什么用,你new XXX他会自动先set nothing

#10


   今天暴力测试了一下,将程序一直开着,然后不停的做操作,发现半小时后必定报out of memory,还是无从下手。
    VB6有没有什么方法可以监控到out of memory时,到底是什么东西导致他这样的?

#11


引用 8 楼  的回复:
按VB6标准的函数与语句来写的话,基本上是不会出现内存泄漏吧,除非使用了非VB6管理以外的东东,比如自己调用API申请内存内存,创建句柄之类,这些不是VB6的管理范围,得编码者自己把握.

+1

#12


按VB6标准的函数与语句来写的话,基本上是不会出现内存泄漏吧,除非使用了非VB6管理以外的东东,比如自己调用API申请内存内存,创建句柄之类,这些不是VB6的管理范围,得编码者自己把握.

循环引用这种情况释放不掉

他的情况应该出在编写者没有使用复制,全用成引用了,再要解开就麻烦了
该复制的时候还是要复制的

#13


不要说没有用,我就经常用 set x=nothing,习惯了。
我还经常用 erase 清除数组,也习惯了。
养成动态回改内存是一种良好的习惯。
因为,计算机同时运行的软件有好多个。

#14


'启动模块中打开日志文件
Option Explicit

Public g_hLogFile As Integer

Sub Main()
    g_hLogFile = FreeFile()
    Open App.Path & "\" & App.EXEName & ".log" For Append As #g_hLogFile
    
    Form1.Show
End Sub

'Form1 主窗体退出时关闭日志
Private Sub Form_Unload(Cancel As Integer)
    Set c1 = Nothing
    Close #g_hLogFile
End Sub

'每个类都写日志:对象指针,类名,创建/释放
Option Explicit

Private Sub Class_Initialize()
    Print #g_hLogFile, Hex(ObjPtr(Me)) & " Class1_Intialize()"
End Sub

Private Sub Class_Terminate()
    Print #g_hLogFile, Hex(ObjPtr(Me)) & " Class1_Terminate()"
End Sub

最终日志如下,对比一下那些对象指针只有 Intialize 没有 Terminate 就是没有释放的。
[Quoto=日志:]3DF3F08 Class1_Intialize()
3DF3EC0 Class2_Intialize()
3DF3EC0 Class2_Terminate()
3DF3F08 Class1_Terminate()[/Quote]

#15


用这个日志就能看到循环引用的没有释放,这是自动化管理没有处理到的
dnet 用扫描算法来清理,吹嘘了好一阵

#16


如老马所说检查API释放,并检查全局VB对象的释放(局部的会自动释放)。

#17


引用 13 楼  的回复:
不要说没有用,我就经常用 set x=nothing,习惯了。
我还经常用 erase 清除数组,也习惯了。
养成动态回改内存是一种良好的习惯。
因为,计算机同时运行的软件有好多个。

+1
这个问题我也遇到了!已经发帖。

#18


引用 15 楼  的回复:
用这个日志就能看到循环引用的没有释放,这是自动化管理没有处理到的
dnet 用扫描算法来清理,吹嘘了好一阵

循环引用的话,引用计数始终不为零,加减不平衡,在当前对象变量范围内确实会引起内存洩漏.

不过当前范围退出后,这些引用计数也是会被清零的.

比如一个在窗体A内实例化的窗体级对象,无论怎样循环引用(除了API操作对象指针等),窗体实例被销毁时还是会被回收的.

但是如果这个对象不是窗体级的,而是全局范围内的,就只有退出程序才能回收了.

这个问题我觉得基本上还是与工程的结构有关系,如何管理代码,如何管理复杂度,就决定了工程能做多大同时还是在完全可控范围内.

这个技术与编码技术几乎无关,平时也很少有文章提及这些,大部分人几乎都是靠自己领悟...比较头疼,我现在工程大小的控制能力就比较小,汗,工程一大就开始乱了.

我见过某知名软件的部分源代码,VB6写的,400多兆,听说完全编译的话需要N台电脑折腾好多小时,真不知道他们如何进行复杂度管理的....

楼主这个问题,要彻底解决的话估计还是要找设计现在工程架构的人,找找结构上的问题,应该能看出点啥的,祝你好运....这可是个头疼的活.

#19


《高级Visual Basic编程(Advanced Visual Basic)》第六章 循环引用
一整章讲这个,足矣。

#20


经过我一个礼拜的测试,似乎已经找到问题所在,只要将Form上的自定义控件拿掉,改用普通控件,暴力测试后没有发生此现象,现在的问题就在于这个user contorls中自己做的自定义控件应该也是个对象,但是对他set nothing说不支持此方法,请教各位自定义控件该怎么释放对象啊?

#1


事实上,set x=nothing并不是必须的,VB在退出过程时会自动清理,你可以编写代码测试,你没有设nothing,但是Class_Terminate()是会执行(意味着自己清理)。关键是,你不能使用循环引用,如果存在循环引用,那你就需要设置nothing

#2


循环引用前好象会自动set nothing

#3


对啊,所以不少对象还有专门的Close,Dispose这类方法啊

#4


这个比较不现实,
除非你将每个对象的生成与销毁都保存下来,写入文件,否者难。

#5


   我现在是这个程序一直开在那边,自动的执行里面很多模块,现在很准时,2天必定WINDOW报out of memory,然后电脑就内存溢出了,只能将这个程序强行关闭,就好了,遇到这个情况我应该怎么去解决呢?

#6


补充一下,是VB执行的时候抛出的ERROR是 OUT OF MEMORY,此时远程连到这台电脑上,发现电脑就是内存溢出了,就像我们平时电脑程序开多了,点什么都没反应

#7


建议楼主仔细检查每个对象,看看有没有使用了没有释放的地方。此外你也可以把你怀疑的地方设置一些写标记语言,把每次用对象的地方都记入文件,以便出问题的时候查阅。

#8


按VB6标准的函数与语句来写的话,基本上是不会出现内存泄漏吧,除非使用了非VB6管理以外的东东,比如自己调用API申请内存内存,创建句柄之类,这些不是VB6的管理范围,得编码者自己把握.

#9


set nothing那玩意真的没什么用,你new XXX他会自动先set nothing

#10


   今天暴力测试了一下,将程序一直开着,然后不停的做操作,发现半小时后必定报out of memory,还是无从下手。
    VB6有没有什么方法可以监控到out of memory时,到底是什么东西导致他这样的?

#11


引用 8 楼  的回复:
按VB6标准的函数与语句来写的话,基本上是不会出现内存泄漏吧,除非使用了非VB6管理以外的东东,比如自己调用API申请内存内存,创建句柄之类,这些不是VB6的管理范围,得编码者自己把握.

+1

#12


按VB6标准的函数与语句来写的话,基本上是不会出现内存泄漏吧,除非使用了非VB6管理以外的东东,比如自己调用API申请内存内存,创建句柄之类,这些不是VB6的管理范围,得编码者自己把握.

循环引用这种情况释放不掉

他的情况应该出在编写者没有使用复制,全用成引用了,再要解开就麻烦了
该复制的时候还是要复制的

#13


不要说没有用,我就经常用 set x=nothing,习惯了。
我还经常用 erase 清除数组,也习惯了。
养成动态回改内存是一种良好的习惯。
因为,计算机同时运行的软件有好多个。

#14


'启动模块中打开日志文件
Option Explicit

Public g_hLogFile As Integer

Sub Main()
    g_hLogFile = FreeFile()
    Open App.Path & "\" & App.EXEName & ".log" For Append As #g_hLogFile
    
    Form1.Show
End Sub

'Form1 主窗体退出时关闭日志
Private Sub Form_Unload(Cancel As Integer)
    Set c1 = Nothing
    Close #g_hLogFile
End Sub

'每个类都写日志:对象指针,类名,创建/释放
Option Explicit

Private Sub Class_Initialize()
    Print #g_hLogFile, Hex(ObjPtr(Me)) & " Class1_Intialize()"
End Sub

Private Sub Class_Terminate()
    Print #g_hLogFile, Hex(ObjPtr(Me)) & " Class1_Terminate()"
End Sub

最终日志如下,对比一下那些对象指针只有 Intialize 没有 Terminate 就是没有释放的。
[Quoto=日志:]3DF3F08 Class1_Intialize()
3DF3EC0 Class2_Intialize()
3DF3EC0 Class2_Terminate()
3DF3F08 Class1_Terminate()[/Quote]

#15


用这个日志就能看到循环引用的没有释放,这是自动化管理没有处理到的
dnet 用扫描算法来清理,吹嘘了好一阵

#16


如老马所说检查API释放,并检查全局VB对象的释放(局部的会自动释放)。

#17


引用 13 楼  的回复:
不要说没有用,我就经常用 set x=nothing,习惯了。
我还经常用 erase 清除数组,也习惯了。
养成动态回改内存是一种良好的习惯。
因为,计算机同时运行的软件有好多个。

+1
这个问题我也遇到了!已经发帖。

#18


引用 15 楼  的回复:
用这个日志就能看到循环引用的没有释放,这是自动化管理没有处理到的
dnet 用扫描算法来清理,吹嘘了好一阵

循环引用的话,引用计数始终不为零,加减不平衡,在当前对象变量范围内确实会引起内存洩漏.

不过当前范围退出后,这些引用计数也是会被清零的.

比如一个在窗体A内实例化的窗体级对象,无论怎样循环引用(除了API操作对象指针等),窗体实例被销毁时还是会被回收的.

但是如果这个对象不是窗体级的,而是全局范围内的,就只有退出程序才能回收了.

这个问题我觉得基本上还是与工程的结构有关系,如何管理代码,如何管理复杂度,就决定了工程能做多大同时还是在完全可控范围内.

这个技术与编码技术几乎无关,平时也很少有文章提及这些,大部分人几乎都是靠自己领悟...比较头疼,我现在工程大小的控制能力就比较小,汗,工程一大就开始乱了.

我见过某知名软件的部分源代码,VB6写的,400多兆,听说完全编译的话需要N台电脑折腾好多小时,真不知道他们如何进行复杂度管理的....

楼主这个问题,要彻底解决的话估计还是要找设计现在工程架构的人,找找结构上的问题,应该能看出点啥的,祝你好运....这可是个头疼的活.

#19


《高级Visual Basic编程(Advanced Visual Basic)》第六章 循环引用
一整章讲这个,足矣。

#20


经过我一个礼拜的测试,似乎已经找到问题所在,只要将Form上的自定义控件拿掉,改用普通控件,暴力测试后没有发生此现象,现在的问题就在于这个user contorls中自己做的自定义控件应该也是个对象,但是对他set nothing说不支持此方法,请教各位自定义控件该怎么释放对象啊?

#21