在 VB6/VBA 中是不是真的需要对象清除/数组释放(优点/缺点?)

Posted

技术标签:

【中文标题】在 VB6/VBA 中是不是真的需要对象清除/数组释放(优点/缺点?)【英文标题】:Is object clearing/array deallocation really necessary in VB6/VBA (Pros/Cons?)在 VB6/VBA 中是否真的需要对象清除/数组释放(优点/缺点?) 【发布时间】:2009-10-06 13:58:35 【问题描述】:

我从使用静态代码分析(特别是 Aivosto 的项目分析器)中学到了很多关于 VB 的知识。它检查的一件事是您是否清除了所有对象和数组。我以前只是盲目地这样做,因为 PA 是这么说的。但是现在我对 VB 释放资源的方式有了更多的了解,在我看来这些事情应该是自动发生的。这是 VB6 之前的遗留功能,还是有理由将对象显式设置为空并在数组上使用 Erase?

【问题讨论】:

【参考方案1】:

Advanced Visual Basic 6 的作者 Matt Curland 对 Visual Basic 的了解比我们大多数人都多,他认为这是浪费精力。考虑一下关于 DAO 的引用 (p110),DAO 是主要针对 Access 数据库引擎的 COM 数据访问库:

另一个糟糕的拆解代码示例。 DAO 有 Close 方法,必须是 以正确的顺序调用,并且 对象必须在 正确的顺序以及(记录集 例如,在数据库之前)。这 单个不良对象模型行为具有 导致了VB泄漏的误解 内存,除非您明确设置所有 局部变量什么都没有 一个函数的结束。这是一个 完全错误的概念 精心设计的对象模型。 VB可以 在结束时更快地清除变量 比您可以从代码中获得的子行,以及 它会检查变量,即使你 明确发布您的参考资料。 你所做的任何努力都是重复的。

【讨论】:

嗨,ODW,这与我的思路相似。 DAO 是我确定必须正确释放的唯一对象(在 Win32 之外)。您是否知道任何其他“特殊情况”?【参考方案2】:

据我了解,问题与 VB6(及其前身)起源于 COM 及其引用计数垃圾收集系统这一事实有关。

例如,假设您声明了对来自 3rd 方库的对象的引用。该对象有一个 COM 引用计数,用于使其保持活动状态并确定何时应将其销毁。当您将其设置为 Nothing 时,它不会被销毁,而是在对象的引用计数达到零时被销毁。

现在,并非所有 COM 组件都是用 Visual Basic 编写的。有些是用 C 或 C++ 编写的。并非所有语言都存在结构化异常处理。因此,如果发生错误,则不能保证正确减少对象的引用计数,并且已知 COM 对象的停留时间比预期的要长。这不是 Visual Basic 本身的问题。这是一个 COM 问题。 (您可能会注意到,这就是 .NET 不使用引用计数的原因。)

这就是为什么 Visual Basic 开发人员对在退出例程之前释放对象引用非常着迷的原因。您根本不知道您分配的组件在后台创建了什么。但是当你释放对它的引用时,你至少释放了对它的引用计数。这几乎成了一种宗教口头禅。宣布、使用、释放。这是 COM 的做事方式。

当然,Visual Basic 在取消引用我在堆栈上声明的变量方面可能会更好或更快。但是该死的,我希望这些对象被释放是显而易见的。当您试图追踪内存泄漏时,一点点保证会有很长的路要走。

【讨论】:

【参考方案3】:

你读过这个Aivosto web page(来自 Project Analyzer 的创建者)吗?

如果您使用的是静态变量, 回收内存很重要 他们在你不需要的时候占据了 变量了。有动态 变量内存不是那么大 问题,因为它们被破坏了 当程序结束时。

换句话说,您无需担心清除普通的、非静态的局部变量。

【讨论】:

+1 注意到这一点:) 虽然我使用静态方法的日子非常罕见。如果我需要记住一些东西,我通常只使用私有模块级变量。【参考方案4】:

我总是这样做是为了良好的实践,如果你陷入其中并且你的对象没有被释放,你永远不知道异常可能会做什么。您应该在 finally 语句中释放它们并确保它们不使用任何内存,否则您可能会遇到内存泄漏。

我在一个简单的休假跟踪系统内部遇到了一个问题,服务器不断随机崩溃,我花了数周时间才确定这是一个应该自行销毁的对象的内存泄漏。我的代码被抛出异常,并且从未清理过,导致服务器(实际的网站而不是整个服务器)宕机。

【讨论】:

有趣,可能会问它是什么类型的对象?它的范围是什么?是抛出了一个可捕获的异常,还是应用程序崩溃了?当抛出标准异常时,程序退出。即使出现异常,所有本地引用仍然会自动销毁。那么,如果在过程之外没有对该对象的引用,那么是什么导致该对象保持“活动”状态? VB6/VBA 中没有 Try/Catch/Finally 块或异常。 没有 Try/Catch/Finally 块,但有可捕获的异常。看看 Err.Raise。 对,我知道VB6中没有,我的意思是可能有类似的东西。很长一段时间没做vb6了抱歉:)。【参考方案5】:

是的,将所有对象设置为 Nothing 并尽可能多地清理。 VB6 因在不清理您的东西时会发生内存泄漏而臭名昭著。垃圾收集在 VB6/VBA 中低于标准。

【讨论】:

嗨,HardCode,我经常听到这种情绪表达。我正在尝试的是一个具体/可重现的例子? VB6 的垃圾回收机制没有任何问题。其他组件没有正确释放引用,或者需要非常特定的拆解语义来破坏它。有写得不好的组件不遵守规则,这不是 VB6 的错。 有时您还需要显式删除诸如循环对象引用之类的内容。一般来说,scope-exit 将释放本地引用并释放数组,但在诸如模块全局数据之类的长期存在的范围内,您可能最好偶尔在战术上提前清理以释放内存资源。关键是没有一般规则。您需要了解自己在做什么以及早期解除分配的价值。 @Bob:好点。我认为我们实际上是同意的:关键在于释放对象并没有硬性规定。 “一切都必须释放-总是-无所谓”的心态似乎源于对可以在任何情况下始终如一地应用的规则的需要,我不能说它是“错误的”工作在这种假设下,但我认为最好了解 GC 在 VB6 中的工作原理,以便您做出明智的决定。困扰我的是人们认为 VB6 的内存管理严重损坏,但这只是一个错误的结论。 感谢 Bob 和 Mike,很好的讨论。我倾向于同意迈克的观点,即你不应该在没有充分理由的情况下做任何事情。而且我认为 Bob 挑衅地提出了一个你可能有充分理由的场景:) +1 2 你们俩:)

以上是关于在 VB6/VBA 中是不是真的需要对象清除/数组释放(优点/缺点?)的主要内容,如果未能解决你的问题,请参考以下文章

在VB6/VBA中使用正则表达式

关于 VB6/VBA 中 CreateObject() 的问题

VB6/VBA中跟踪鼠标移出窗体控件事件(类模块成员函数指针CHooker类应用)

Spring中的HTTP请求后我们是不是需要清除MDC

如何检查 Tailwind 是不是真的清除了 CSS?

检查布尔数组中的所有值是不是为真的最优雅方法是啥?