我从使用静态代码分析(特别是 Aivosto 的项目分析器)中学到了很多关于 VB 的知识。它检查的一件事是您是否清除了所有对象和数组。我以前只是盲目地这样做,因为 PA 是这么说的。但是现在我对 VB 释放资源的方式有了更多的了解,在我看来这些事情应该是自动发生的。这是 VB6 之前的遗留功能,还是有理由将对象显式设置为空并在数组上使用 Erase?
5 回答
高级 Visual Basic 6的作者 Matt Curland 对Visual Basic的了解比我们大多数人都多,他认为这是浪费精力。考虑一下关于 DAO 的引用 (p110),DAO 是主要针对 Access 数据库引擎的 COM 数据访问库:
另一个糟糕的拆解代码示例。DAO 具有必须以正确顺序调用的 Close 方法,并且对象也必须以正确的顺序释放(例如,Recordset 在 Database 之前)。这种单一的不良对象模型行为导致了一种误解,即 VB 会泄漏内存,除非您在函数结束时将所有局部变量显式设置为空。在精心设计的对象模型中,这是一个完全错误的概念。VB 可以比您从代码中更快地清除 End Sub 行中的变量,并且即使您明确释放引用,它也会检查变量。你所做的任何努力都是重复的。
据我了解,这个问题与 VB6(及其前身)起源于 COM 及其引用计数垃圾收集系统这一事实有关。
例如,假设您声明了对来自 3rd 方库的对象的引用。该对象有一个 COM 引用计数,用于使其保持活动状态并确定何时应将其销毁。当您将其设置为 Nothing 时,它不会被销毁,但当对象的引用计数达到零时。
现在,并不是所有的 COM 组件都是用 Visual Basic 编写的。有些是用 C 或 C++ 编写的。并非所有语言都存在结构化异常处理。因此,如果发生错误,则不能保证正确减少对象上的引用计数,并且已知 COM 对象的停留时间比预期的要长。这不是 Visual Basic 本身的问题。这是一个 COM 问题。(您可能会注意到,这就是 .NET 不使用引用计数的原因。)
这就是为什么 Visual Basic 开发人员对在退出例程之前释放对象引用非常着迷的原因。您根本不知道您分配的组件在后台创建了什么。但是当你释放对它的引用时,你至少释放了对它的引用计数。这几乎成了一种宗教口头禅。宣布、使用、释放。这是 COM 的做事方式。
当然,Visual Basic 在取消引用我在堆栈上声明的变量方面可能会更好或更快。但是该死的,我希望这些对象被释放是显而易见的。当您试图追踪内存泄漏时,一点点保证会有很长的路要走。
您是否阅读过此Aivosto 网页(来自 Project Analyzer 的创建者)?
如果您使用的是静态变量,那么当您不再需要这些变量时,回收它们占用的内存很重要。使用动态变量,内存不是什么大问题,因为它们在过程结束时被销毁。
换句话说,您无需担心清除普通的、非静态的局部变量。
我总是这样做是为了良好的实践,如果你陷入其中并且你的对象没有被释放,你永远不知道异常可能会做什么。您应该在 finally 语句中释放它们并确保它们不使用任何内存,否则您可能会遇到内存泄漏。
我在一个简单的休假跟踪系统内部遇到了一个问题,服务器一直随机崩溃,我花了数周时间才确定这是一个应该自行销毁的对象的内存泄漏。我的代码被抛出异常,并且在自身导致服务器(实际网站而不是整个服务器)关闭后从未清理过。
是的,将所有对象设置为 Nothing 并尽可能多地清理。VB6 因在不清理您的东西时会发生内存泄漏而臭名昭著。垃圾收集在 VB6/VBA 中低于标准。