Declaring Variables Memory Leaks

2020-02-13 06:01发布

问题:

I am wondering what would be the most correct way to deal with memory when using VBScript. Should declare all variables right before I use them? The beginning of the program? I understand global vs local, however in my script all variables are local. I know that memory leaks will never be a problem when writing in VBScript 99.9% of the time, but I am also curious as to the 'best' way to clear and release memory within a script. By 'best' I mean, the timing of clearing variables/objects (right after you are done using them vs the end of the script), etc.

An example:

Dim fso: Set fso = CreateObject("Scripting.FileSystemObject")
Dim arrList : Set arrList = CreateObject("System.Collections.ArrayList")
Dim objDict: Set objDic  = CreateObject( "Scripting.Dictionary")
Dim objEmail : Set objEmail = CreateObject("CDO.Message")

Dim someArray(), x, y, z, item

回答1:

The VBScript garbage collector runs at the end of every line to clear implicit variables and at the end of every procedure (end sub, end function, and end property) to clear explicit variables. Objects are similar but have added constraints. It works similar to VBA's garbage collector. By contrast JScript waits until 30,000 objects have gone out of scope before running and freeing memory.

An implicit variable is an unnamed variable - msgbox LCase(UCase("String") has two implicit variables - the result of UCase("String") and that is passed to LCase(implicitVar1) which returns implicitVar2 which is passed to Msgbox. An Explict variable is declared either by DIM or just by using it as in A=5 which creates an explicit variable called A.

VBScript, on the other hand, has a much simpler stack-based garbage collector. Scavengers are added to a stack when they come into scope, removed when they go ou t of scope, and any time an object is discarded it is immediately freed.

https://blogs.msdn.microsoft.com/ericlippert/2003/09/17/how-do-the-script-garbage-collectors-work/

VBScript’s garbage collector is completely different. It runs at the end of every statement and procedure, and does not do a search of all memory. Rather, it keeps track of everything allocated in the statement or procedure; if anything has gone out of scope, it frees it immediately

https://blogs.msdn.microsoft.com/ericlippert/2004/12/22/t4-vbscript-and-the-terminator/

Also

https://blogs.msdn.microsoft.com/ericlippert/2004/04/28/when-are-you-required-to-set-objects-to-nothing/

https://blogs.msdn.microsoft.com/ericlippert/2004/03/01/syntax-semantics-micronesian-cults-and-novice-programmers/

The CPU is a stack based machine (and VBScript a stack based virtual machine). When the CPU calls a function the calling program puts the parameters on the stack and the return address, adjust the stack frame and does a jump. The callee function creates local variables on the stack and also places the return value on it. When it returns the stack pointer is adjusted back to where it was which automatically frees all the above.



回答2:

It's best practice to declare all variables, but not for the reason you assume. VBScript is sufficiently good at cleaning up after itself, so memory leaks usually aren't an issue. Most of the time you don't even need to release objects (Set var = Nothing) because they're automatically destroyed when leaving the context.

The reason why you still want to declare your variables is that you want to use Option Explicit in your scripts (which enforces variable declarations), so that you can avoid problems due to mistyped or otherwise uninitialized variables. Without Option Explicit VBScript would automagically create missing variables and initialize them with an empty/zero value. Silly example:

Dim foo : foo = 3
Dim bar : bar = 1
Do
  bar = bar + fo     'mistyped variable, initilized as empty/0
Loop Until bar > 10
WScript.Echo bar

Running the above would create an infinite loop. If you add Option Explicit the script will instead immediately terminate with a runtime error:

C:\path\to\your.vbs(5, 3) Microsoft VBScript runtime error: Variable is undefined: 'fo'