JavaScript doesn't have a concept of destructors like many OO languages,
but in a server-side context, there's a real need for them. Garbage collection in JavaScript is done behind the scenes on objects that are no longer referenced. When would you call an object's destructor: 1) when it is no longer referenced, or 2) when it is garbage collected?
I suggest that if we could have some "destructor" support in v8, that it be the former (no longer referenced). It is critical in server-side environments that any (external) resources can be freed as soon as possible. For example, there are a limited number of file descriptors (fds) available to a Unix/Linux system, and if they're all tied up (open) in some JS object that's been dereferenced, the server can run out of them. If you deal with fds in wrapped C++ classes made as weak references, those fds can be tied up for a long long time, until v8 maybe decides to GC and call the weak callback. But if there were a mechanism to register a callback to be called when an object is no longer referenced, the fds could be closed and released to the OS/application for reuse long before V8 maybe decides to garbage collect.
I note that JavaScript 1.8.5 provides this:
I've been fed the line that garbage collection, as done in languages like C#, Java, JavaScript, et al, was meant to free the programmer from making certain mistakes. The answer that we should manually call a destroy() type function because we know it's a good time to do so suggests we should call delete (operator) as well for every object we call new (operator).
The ECMAScript 1.8.5 method I referenced is an example of how the language (or environment) has evolved to address things lacking in previous versions (such as the ability to protect properties from deletion).
On Tuesday, July 10, 2012 6:57:54 AM UTC-7, Andreas Rossberg wrote:On 10 July 2012 15:33, mschwartz <myk...@gmail.com> wrote:JavaScript doesn't have a concept of destructors like many OO languages,
I think "most OO languages" is an exaggeration. Rather, it is an artifact of the few (though popular) OO-languages with manual memory management.but in a server-side context, there's a real need for them. Garbage collection in JavaScript is done behind the scenes on objects that are no longer referenced. When would you call an object's destructor: 1) when it is no longer referenced, or 2) when it is garbage collected?In practice, there is no difference between (1) and (2), because you cannot generally find out that something is no longer referenced except by doing (most of the work of) a garbage collection. At least not in a language with first-class functions and objects.I suggest that if we could have some "destructor" support in v8, that it be the former (no longer referenced). It is critical in server-side environments that any (external) resources can be freed as soon as possible. For example, there are a limited number of file descriptors (fds) available to a Unix/Linux system, and if they're all tied up (open) in some JS object that's been dereferenced, the server can run out of them. If you deal with fds in wrapped C++ classes made as weak references, those fds can be tied up for a long long time, until v8 maybe decides to GC and call the weak callback. But if there were a mechanism to register a callback to be called when an object is no longer referenced, the fds could be closed and released to the OS/application for reuse long before V8 maybe decides to garbage collect.
You are talking about finalization. It is folklore that using finalization for managing resources other than memory (especially limited resources like OS handles) is almost always a bad idea, because garbage collection is far too non-deterministic for that. You will have no guarantee that finalizers are invoked in a timely manner, because the GC cannot tell.I note that JavaScript 1.8.5 provides this:Maybe I misunderstand, but Object.defineProperty is perfectly standard ES5 functionality, and fully supported by V8. Where do you see the connection to finalization?/Andreas
I think we're in 100% agreement that finalization time is a poor time to manage resource deallocation. This is the point of my suggestion that there be some mechanism to register a destructor with the JS engine for the object that is called when completely dereferenced.
The ECMAScript 1.8.5 method I referenced is an example of how the language (or environment) has evolved to address things lacking in previous versions (such as the ability to protect properties from deletion).
meant to free the programmer from making certain mistakes. The answer that we should manually call a destroy() type function because we know it's a good time to do so suggests we should call delete (operator) as well for every object we call new (operator).
You left out the best part of my last post. I'll try again, but this time with a more concrete example.
GC finalization actually works for SilkJS. In the HTTP server, there are two nested loops. The outer loop waits for connections, the inner loop handles keep-alive requests. At the end of the inner loop (e.g. when the connection is about to be closed), I force a GC (or at least try to).
2) V8′s idle garbage collection is disabled via “–nouse-idle-notification”
This was critical, as the server pre-allocates over 2 million JS Objects for the network topology. If you don’t disable idle garbage collection, you’ll see a full second of delay every few seconds, which would be an intolerable bottleneck to scalability and responsiveness. The delay appears to be caused by the garbage collector traversing this list of objects, even though none of them are actually candidates for garbage collection.
In any case, before you conclude that finalization is the answer to your problems, let me +1 Sven's recommendation on reading Boehm's paper on the subject. Finalization is pretty much an anti-pattern. There are some rare, low-level use cases, but usually it creates more problems than it solves. That's why we only provide it in the C++ API.
Section 3.3, bullet point #1: "There is usually not much of a point in writing a finalizer that touched only the object being finalized, since
Sorry for top posting (tablet gmail makes it difficult to do otherwise)...
I should have specied that correct, well-defined behaviour is far, far more important to me than gc-related lags. For me it has never been a question of performance, but of well-defined (non- performance- related) behaviours and returning resources to their owners. Yes, i use finalizers for all of my bound native types, but that is so that they have well-defined behaviour and has 0 to do with speed. Obviously that requirement is out of scope for chromium, which is fine in and of itself but very negatively impacts v8's re-use in other projects because we embedders often have to expend undue amounts of energy shoe-horning finalization into not only our c++ code but also into our docs and users. (Yes, it's our own fault, but without bindings to interesting natives js is not much use.)
--