Fabulous Adventures In Coding
Eric Lippert is a principal developer on the C# compiler team. Learn more about Eric.
UPDATE: This article was written in 2003. Since that time the JScript garbage collector has been completely rewritten so as to be more performant in general, to handle the larger working sets entailed by modern web applications that we had absolutely no idea were coming when we designed the JScript GC back in 1995, to be better at predicting when there is garbage that needs collecting, and to be better at handling circular references involving browser objects. I did not do any of that work; I haven't worked on the script team for almost a decade now. I do not know how the modern JScript GC works; I've had the architect describe the basics to me but I am not an expert on it. This article should be considered "for historical purposes only"; it does not reflect how JScript works today.
JScript and VBScript both are automatic storage languages. Unlike, say, C++, the script developer does not have to worry about explicitly allocating and freeing each chunk of memory used by the program. The internal device in the engine which takes care of this task for the developer is called the garbage collector.
Interestingly enough though, JScript and VBScript have completely different garbage collectors. Occasionally people ask me how the garbage collectors work and what the differences are.
JScript uses a nongenerational mark-and-sweep garbage collector. It works like this:
Actually it is a little more complex than that, as we must worry about details like "what if freeing an item causes a message loop to run, which handles an event, which calls back into the script, which runs code, which triggers another garbage collection?" But those are just implementation details. (Incidentally, every JScript engine running on the same thread shares a GC, which complicates the story even further.)
You'll note that I hand-waved a bit there when I said "every now and then..." Actually what we do is keep track of the number of strings, objects and array slots allocated. We check the current tallies at the beginning of each statement, and when the numbers exceed certain thresholds we trigger a collection.
The benefits of this approach are numerous, but the principle benefit is that circular references are not leaked unless the circular reference involves an object not owned by JScript.
However, there are some down sides as well. Performance is potentially not good on large-working-set applications -- if you have an app where there are lots of long-term things in memory and lots of short-term objects being created and destroyed then the GC will run often and will have to walk the same network of long-term objects over and over again. That's not fast.
The opposite problem is that perhaps a GC will not run when you want one to. If you say "blah = null" then the memory owned by blah will not be released until the GC releases it. If blah is the sole remaining reference to a huge array or network of objects, you might want it to go away as soon as possible. Now, you can force the JScript garbage collector to run with the CollectGarbage() method, but I don't recommend it. The whole point of JScript having a GC is that you don't need to worry about object lifetime. If you do worry about it then you're probably using the wrong tool for the job.
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 out of scope, and any time an object is discarded it is immediately freed.
You might wonder why we didn't put a mark-and-sweep GC into VBScript. There are two reasons. First, VBScript did not have classes until version 5, but JScript had objects from day one; VBScript did not need a complex GC because there was no way to get circular references in the first place! Second, VBScript is supposed to be like VB6 where possible, and VB6 does not have a mark-n-sweep collector either.
The VBScript approach pretty much has the opposite pros and cons. It is fast, simple and predictable, but circular references of VBScript objects are not broken until the engine itself is shut down.
The CLR GC is also mark-n-sweep but it is generational – the more collections an object survives, the less often it is checked for life. This dramatically improves performance for large-working-set applications. Of course, the CLR GC was designed for industrial-grade applications, the JScript GC was designed for simple little web pages.
What happens when you have a web page, ASP page or WSH script with both VBScript and JScript? JScript and VBScript know nothing about each others garbage collection semantics. A VBScript program which gets a reference to a JScript object just sees another COM object. The same for a VBScript object passed to JScript. A circular reference between VBScript and JScript objects would not be broken and the memory would leak (until the engines were shut down). A noncircular reference will be freed when the object in question goes out of scope in both language (and the JS GC runs.)
I too hope this bug will be fixed in IE8
PingBack from http://www.sitepen.com/blog/2008/06/09/string-performance-getting-good-performance-from-internet-explorer/
I have a question.
document.getElementById("div1").onclick = makedb(document.getElementById("div1")
So, this is the memory leak, since the div DOM/COM Object is not managed by JScript GC. and will not marked nor sweep.
but under recycle reference, div1 -> js closure ->div1 .
the "js closure" created by makedb, will be GCed or not ?
i doens't seem any "scavenger" reference to it.
In IE7 and earlier:
The garbage collector will release it, but of course div1 is also holding onto a reference to the closure. Only when all the references are gone will it go away. But we have a circular reference, so the reference will never go away. Therefore, memory leak.
In IE8: The garbage collector has been rewritten so that IE-owned objects participate in the garbage collection process. This should not leak anymore.
Hope IE8 will take international standards.. then it shouldnt be a problem just like FireFox.
The garbage collector distribution includes a C string package that provides for fast concatenation and substring operations on long strings. A simple curses- and win32-based editor that represents the entire file as a cord is included as a sample application.
PingBack from http://blueboxsols.com/?p=1813
All these different ways of coding and different programming languages. I wonder where we would be if everybody would be using the same computer language...
PingBack from http://vinaytech.wordpress.com/2008/11/07/garbage-collection-in-ie6/
Anyway, the point is JScript is VERY bad at cleaning up after its self - in my opinion it very much should be up to you as a programmer to clean up after yourself. The CollectGarbage(); was exactly the trick I was looking for.
Our servers where almost always falling over with memory build-up. I could actually sit there and watch our servers build all the way up to about 1 gig... after that the server will slow down to a halt. The only fix this was to set the Recycle to about 120min. This cleared the pipes but did not fix the problem. Our clients kept getting logged out since the Recycle drops the sessions.
I know there were a number of things we could have done - however changing all the code to VB simply was not in budget. There are hundreds of thousands of lines of code and custom built client modules... simply an impossible task.
That was until I read this post. I simply added <% CollectGarbage(); %> to the last line of code in the last include. So basically once everything was completed and executed... clean-up! Wow. My jaw dropped as I saw the memory drop, drop, drop...
There have simply been no more problems since this! Look I'm pretty sure that we have quite a unique situation, but if anyone else is out there starching their heads about this problem. Try it, worked for me.
PingBack from http://v9.pupius.co.uk/blog/2007/03/garbage-collection-in-ie6/