VBScript memory leaks

Author Message
TNO

  • Total Posts : 2094
  • Scores: 36
  • Reward points : 0
  • Joined: 12/18/2004
  • Location: Earth
  • Status: offline
VBScript memory leaks Wednesday, December 06, 2006 9:58 PM (permalink)
0
An important issue that has been ignored/overlooked in my opinion is the issue with memory leaks. In 99% of situations this isn't an issue, but if you ever plan to use your scripts in an HTA, or any other envireonment where it will be open for more than a few minutes than this will apply to you:

First off, what is a memory leak?

A memory leak is a particular kind of unintentional memory consumption by a program where the program fails to release memory when no longer needed. resulting in that program subsequently losing the ability to access it due to program logic flaws.

So what are consequences of having memory leaks?

This can result in your entire computer losing its efficiency due to the loss of RAM and virtual memory. So the result of a memory leak is usually an ever growing amount of memory being used by the system as a whole, not merely by the erroneous process or program. Like I said earlier, in most cases this isn;t an issue whent he program only runs for short periods of time, but when you start to build higher end applications it will pose a significant issue. For example, I'm developing a large database manipulation application for the Logisitics guys here in Iraq, but because of its memory leaks it will crash if its left on overnight. Nothing technically wrong with the programming itself, but an inherent problem with how memory allocation is handled by MSHTA.exe (garbage collecting) is whats causing the issue.

So what does it look like?

Heres a simple example of a vbscript that will cause a memory leak:

  Class MyClass
      Public Foo
  End Class
  Set X = New MyClass
  Set Y = New MyClass
  
  Set X.Foo = Y
  Set Y.Foo = X
  
  Set X = Nothing
  Set Y = Nothing


At the end of this script, neither X nor Y have been released because each still has another object referencing it. Yet you now have no way of getting to that memory because all the variable references have been thrown away. This is a circular reference memory leak. Unlike its brother, JScript, vbscript does not have a circular reference detector. but fortunately, as soon as your program closes, this memory leak is corrected, the engine breaks all the circular references and destroys all unterminated objects.

a quote from MSDN for ASP related issues:


A somewhat more technical problem can arise when using VBScript classes on the ASP Web server. The ASP server is multithreaded and assigns a different thread to each page request (and hence each script engine). But VBScript class instances are apartment-threaded objects, which means that they must run on the thread that created them. Therefore, attempts to use one instance of a VBScript class on two different pages via storage in Session or Application scope are doubly doomed to failure. First of all, since apartment-threaded objects must run on the same thread, but different pages are on different threads, you'll take a major performance hit if you use one object on two pages with Session scope. Any calls on the second thread have to be marshaled back to the first thread, which is both a source of resource contention and simply a slow operation. Putting apartment-threaded objects into Session scope is not recommended, and putting them into Application scope is illegal. However, that point is somewhat moot because, as I mentioned earlier, when the script engine shuts down, all of the objects that it owns are terminated.
Remember, the methods of a class are script and therefore need a script engine to run them. When the page associated with the class is served to the client, the script engine that created the class is closed and all the class instances go with it.


Another problem:

Anytime you work with the browser, wether it be Internet Explore or an HTML Application, you have a serious possibility of creating memory leaks that can't be fixed by just closing the program Generally speaking attaching an event to tag elements can create memory leaks since the browser/HTA never knows when it can delete either. Thus, it never does. (it never knows when you're done listening for an event). So a good way to fix it is with something similar to this:

someobject.eventListener = undefined;
or
someobject.eventListener = Nothing;

This is just an introduction to the problem and the possible solution. If you have more to add please do, I'd like to hear your experiences with this issue



To iterate is human, to recurse divine. -- L. Peter Deutsch
 
#1
    ginolard

    • Total Posts : 1347
    • Scores: 23
    • Reward points : 0
    • Joined: 8/11/2005
    • Status: offline
    RE: VBScript memory leaks Wednesday, December 06, 2006 10:53 PM (permalink)
    0
    Haven't the Scripting Guys established long ago that setting objects to Nothing in Vbscript achieves exactly that.

    Nothing.
    Author of ManagePC - http://managepc.net

     
    #2
      ehvbs

      • Total Posts : 3321
      • Scores: 110
      • Reward points : 0
      • Joined: 6/22/2005
      • Location: Germany
      • Status: offline
      RE: VBScript memory leaks Thursday, December 07, 2006 12:46 AM (permalink)
      0

      Use
        for %i in (1,2,3,4,5) do cscript nothing.vbs %i

      to call

        ' ############################################################################
        ''# Nothing.vbs - demonstrates Nothing
        ' ############################################################################
        
        Option Explicit
        
        ' ############################################################################
        ''#
        ' ############################################################################
        
        Class cNothing
        
          Public m_sName
          Public m_oOther
        
          Private Sub Class_Initialize()
            WScript.Echo "cNothing::Class_Initialize() called."
          End Sub
        
          Private Sub Class_Terminate()
            WScript.Echo "cNothing::Class_Terminate() called for " + m_sName + "."
          End Sub
        
          Public Function named( sName )
            m_sName = sName
            Set named = Me
          End Function
        
        End Class
        
        ' ############################################################################
        ''# main
        ' ############################################################################
        
        Dim oFrs, oSec
        
        Select Case WScript.Arguments( 0 )
           Case 1
             WScript.Echo "(1) Start of Main"
             WScript.Echo "Frs.Class_Terminate will be called after EndOfMain"
             Set oFrs = New cNothing.named( "Frs" )
             WScript.Echo "End of Main"
           Case 2
             WScript.Echo "(2) Start of Main"
             WScript.Echo "Thanks to nothing, Frs.Class_Terminate will be called before EndOfMain"
             Set oFrs = New cNothing.named( "Frs" )
             Set oFrs = Nothing
             WScript.Echo "End of Main"
           Case 3
             WScript.Echo "(3) Start of Main"
             WScript.Echo "Thanks to nothing, both destructors will be called before EndOfMain"
             Set oFrs = New cNothing.named( "Frs" )
             Set oSec = New cNothing.named( "Sec" )
             Set oSec = Nothing
             Set oFrs = Nothing
             WScript.Echo "End of Main"
           Case 4
             WScript.Echo "(4) Start of Main"
             WScript.Echo "After marriage (circular reference), nothing works no more."
             WScript.Echo "The reaper reaps after EndOfMain"
             Set oFrs = New cNothing.named( "Frs" )
             Set oSec = New cNothing.named( "Sec" )
             Set oFrs.m_oOther = oSec
             Set oSec.m_oOther = oFrs
             Set oSec = Nothing
             Set oFrs = Nothing
             WScript.Echo "End of Main"
           Case 5
             WScript.Echo "(5) Start of Main"
             Set oFrs = New cNothing.named( "Frs" )
             Set oSec = New cNothing.named( "Sec" )
             Set oFrs.m_oOther = oSec
             Set oSec.m_oOther = oFrs
             WScript.Echo "other of Frs: " + oFrs.m_oOther.m_sName
             WScript.Echo "other of Sec: " + oSec.m_oOther.m_sName
             Set oSec = Nothing
        On Error Resume Next
             WScript.Echo "other of Sec: " + oSec.m_oOther.m_sName
             WScript.Echo "*** " + Err.Description + " ***"
        On Error GoTo 0
             WScript.Echo "other of Sec (via Frs.m_oOther): " + oFrs.m_oOther.m_oOther.m_sName
             WScript.Echo "QED: oSec still lives, but can't be accessed via oSec variable."
             WScript.Echo "End of Main"
        End Select
        


      That will give you something like

        C:\wis\_vbs\0506\dev\forum
        cscript nothing.vbs 1
        (1) Start of Main
        Frs.Class_Terminate will be called after EndOfMain
        cNothing::Class_Initialize() called.
        End of Main
        cNothing::Class_Terminate() called for Frs.
        
        C:\wis\_vbs\0506\dev\forum
        cscript nothing.vbs 2
        (2) Start of Main
        Thanks to nothing, Frs.Class_Terminate will be called before EndOfMain
        cNothing::Class_Initialize() called.
        cNothing::Class_Terminate() called for Frs.
        End of Main
        
        C:\wis\_vbs\0506\dev\forum
        cscript nothing.vbs 3
        (3) Start of Main
        Thanks to nothing, both destructors will be called before EndOfMain
        cNothing::Class_Initialize() called.
        cNothing::Class_Initialize() called.
        cNothing::Class_Terminate() called for Sec.
        cNothing::Class_Terminate() called for Frs.
        End of Main
        
        C:\wis\_vbs\0506\dev\forum
        cscript nothing.vbs 4
        (4) Start of Main
        After marriage (circular reference), nothing works no more.
        The reaper reaps after EndOfMain
        cNothing::Class_Initialize() called.
        cNothing::Class_Initialize() called.
        End of Main
        cNothing::Class_Terminate() called for Frs.
        cNothing::Class_Terminate() called for Sec.
        
        C:\wis\_vbs\0506\dev\forum
        cscript nothing.vbs 5
        (5) Start of Main
        cNothing::Class_Initialize() called.
        cNothing::Class_Initialize() called.
        other of Frs: Sec
        other of Sec: Frs
        *** Objekt erforderlich ***
        other of Sec (via Frs.m_oOther): Frs
        QED: oSec still lives, but can't be accessed via oSec variable.
        End of Main
        cNothing::Class_Terminate() called for Frs.
        cNothing::Class_Terminate() called for Sec.
        


      From that you see:

        (1) Set oX = Nothing will decrement the reference counter of oX. If
            this counter reaches 0, oX will be destructed and its memory
            released. The destructor could do other important stuff like
            closing files or destroying 'big' variables (e.g. a dictionary
            containing many items). So being able to specify the moment
            when destruction takes place is valuable (Scripting Guys and
            their opinions not withstanding).

        (2) Circular references make it more difficult to achieve this
            goal. But it's not impossible. Can you add code to nothing.vbs
            to get:

              cscript nothing.vbs 6
              (6) Start of Main
              After marriage (circular reference) everything works if you work for it.
              cNothing::Class_Initialize() called.
              cNothing::Class_Initialize() called.
              cNothing::Class_Terminate() called for Sec.
              cNothing::Class_Terminate() called for Frs.
              End of Main

       
      #3
        TNO

        • Total Posts : 2094
        • Scores: 36
        • Reward points : 0
        • Joined: 12/18/2004
        • Location: Earth
        • Status: offline
        RE: VBScript memory leaks Thursday, December 07, 2006 12:53 AM (permalink)
        0
        Sad to say I take everything the scriptng guys say with a grain of salt.....

        But ultimately the purpose is to remove any pointers to your objects when your done with them so the garbage collector can clean them up.
        To iterate is human, to recurse divine. -- L. Peter Deutsch
         
        #4

          Online Bookmarks Sharing: Share/Bookmark

          Jump to:

          Current active users

          There are 0 members and 1 guests.

          Icon Legend and Permission

          • New Messages
          • No New Messages
          • Hot Topic w/ New Messages
          • Hot Topic w/o New Messages
          • Locked w/ New Messages
          • Locked w/o New Messages
          • Read Message
          • Post New Thread
          • Reply to message
          • Post New Poll
          • Submit Vote
          • Post reward post
          • Delete my own posts
          • Delete my own threads
          • Rate post

          2000-2012 ASPPlayground.NET Forum Version 3.9