|
|
@ -1,6 +1,8 @@ |
|
|
|
<h1 id="finalization">Finalization</h1> |
|
|
|
|
|
|
|
<h2>Overview of finalization</h2> |
|
|
|
<p>Duktape supports object finalization as a custom feature. A finalizer |
|
|
|
is called when an object is about to be freed, so that application code |
|
|
|
can e.g. free native resources associated with an object.</p> |
|
|
|
|
|
|
|
<p>An object which has an internal finalizer property in its prototype |
|
|
|
chain (or in the object itself) is subject to finalization before being |
|
|
@ -30,83 +32,5 @@ freeing a native resource twice in such cases.</p> |
|
|
|
can currently be any coroutine in the heap. (This will be fixed in the future.) |
|
|
|
</p> |
|
|
|
|
|
|
|
<h2>Simple example</h2> |
|
|
|
|
|
|
|
<p>Finalization example:</p> |
|
|
|
<pre class="ecmascript-code"> |
|
|
|
// finalize.js |
|
|
|
var a; |
|
|
|
|
|
|
|
function init() { |
|
|
|
a = { foo: 123 }; |
|
|
|
|
|
|
|
Duktape.fin(a, function (x) { |
|
|
|
try { |
|
|
|
print('finalizer, foo ->', x.foo); |
|
|
|
} catch (e) { |
|
|
|
print('WARNING: finalizer failed (ignoring): ' + e); |
|
|
|
} |
|
|
|
}); |
|
|
|
} |
|
|
|
|
|
|
|
// create object, reference it through 'a' |
|
|
|
init(); |
|
|
|
|
|
|
|
// delete reference, refcount triggers finalization immediately |
|
|
|
print('refcount finalizer'); |
|
|
|
a = null; |
|
|
|
|
|
|
|
// mark-and-sweep finalizing happens here (at the latest) if |
|
|
|
// refcounting is disabled |
|
|
|
print('mark-and-sweep finalizer') |
|
|
|
Duktape.gc(); |
|
|
|
</pre> |
|
|
|
|
|
|
|
<p>The <code>try-catch</code> wrapper inside the finalizer of the above |
|
|
|
example is strongly recommended. An uncaught finalizer error is silently |
|
|
|
ignored which can be confusing, as it may seem like the finalizer is not |
|
|
|
getting executed at all.</p> |
|
|
|
|
|
|
|
<p>If you run this with the Duktape command line tool (with the default |
|
|
|
Duktape profile), you'll get:</p> |
|
|
|
<pre> |
|
|
|
$ duk finalize.js |
|
|
|
refcount finalizer |
|
|
|
finalizer, foo -> 123 |
|
|
|
mark-and-sweep finalizer |
|
|
|
Cleaning up... |
|
|
|
</pre> |
|
|
|
|
|
|
|
<h2>Adding a finalizer to a prototype object</h2> |
|
|
|
|
|
|
|
<p>If you have many objects of the same type, you can add a finalizer to the |
|
|
|
prototype to minimize the property count of object instances:</p> |
|
|
|
<pre class="ecmascript-code"> |
|
|
|
// Example of a hypothetical Socket object which is associated with a |
|
|
|
// platform specific file descriptor. |
|
|
|
|
|
|
|
function Socket(host, port) { |
|
|
|
this.host = host; |
|
|
|
this.port = port; |
|
|
|
this.fd = Platform.openSocket(host, port); |
|
|
|
} |
|
|
|
Duktape.fin(Socket.prototype, function (x) { |
|
|
|
if (x === Socket.prototype) { |
|
|
|
return; // called for the prototype itself |
|
|
|
} |
|
|
|
if (typeof x.fd !== 'number') { |
|
|
|
return; // already freed |
|
|
|
} |
|
|
|
try { |
|
|
|
Platform.closeSocket(x.fd); |
|
|
|
} catch (e) { |
|
|
|
print('WARNING: finalizer failed for fd ' + x.fd + ' (ignoring): ' + e); |
|
|
|
} |
|
|
|
delete x.fd; |
|
|
|
}); |
|
|
|
|
|
|
|
// Any Socket instances are now finalized without registering explicit |
|
|
|
// finalizers for them: |
|
|
|
|
|
|
|
var sock = new Socket('localhost', 8080); |
|
|
|
</pre> |
|
|
|
<p>See <a href="http://wiki.duktape.org/HowtoFinalization">How to use finalization</a> |
|
|
|
for examples.</p> |
|
|
|