mirror of https://github.com/svaarala/duktape.git
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
129 lines
6.2 KiB
129 lines
6.2 KiB
<h1 id="finalization">Finalization</h1>
|
|
|
|
<h2>Overview</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 the object. The finalizer
|
|
can be either an ECMAScript function or a Duktape/C function. However,
|
|
ECMAScript finalizers may interact badly with script timeouts, see below.</p>
|
|
|
|
<p>See <a href="http://wiki.duktape.org/HowtoFinalization.html">How to use finalization</a>
|
|
for examples.</p>
|
|
|
|
<h2>Getting and setting the current finalizer</h2>
|
|
|
|
<p>An object which has an internal <code>_Finalizer</code> property in its
|
|
prototype chain (or in the object itself) is subject to finalization before
|
|
being freed. The internal property should not be accessed directly, but can
|
|
be read/written using the following:</p>
|
|
<ul>
|
|
<li><code>Duktape.fin(obj)</code> (ECMAScript) or
|
|
<code>duk_get_finalizer()</code> (C)
|
|
gets the current finalizer.</li>
|
|
<li><code>Duktape.fin(obj, fn)</code> (ECMAScript) or
|
|
<code>duk_set_finalizer()</code> (C)
|
|
sets the current finalizer.</li>
|
|
</ul>
|
|
|
|
<h2>Finalizer function arguments and return value</h2>
|
|
|
|
<p>The finalizer function is called with two arguments:</p>
|
|
<ul>
|
|
<li>The object being finalized.</li>
|
|
<li>A boolean flag indicating if the object is being forcibly freed as part
|
|
of heap destruction. This argument was added in Duktape 1.4.0:
|
|
<ul>
|
|
<li>If <code>false</code> (normal case), the finalizer may rescue the object
|
|
by creating a live reference to the object before returning and the
|
|
finalizer is guaranteed to be called again later (heap destruction at
|
|
the latest).</li>
|
|
<li>If <code>true</code> (forced finalization in heap destruction), the
|
|
object cannot be rescued and will be forcibly freed after the finalizer
|
|
finishes. Native resources should be freed without expecting any further
|
|
calls into the finalizer.</li>
|
|
</ul>
|
|
</li>
|
|
</ul>
|
|
|
|
<p>The return value of a finalizer is ignored. Any errors thrown by the
|
|
finalizer are also silently ignored.</p>
|
|
|
|
<h2>Finalizer execution guarantees</h2>
|
|
|
|
<p>The main finalizer guarantees are:</p>
|
|
<ul>
|
|
<li>Finalizers are executed for unreachable objects detected by reference
|
|
counting or mark-and-sweep. The finalizer may not execute immediately,
|
|
however, not even when reference counting detects that the object became
|
|
unreachable.</li>
|
|
<li>Finalizers are also executed for all remaining objects, regardless of
|
|
their reachability status, when a Duktape heap is destroyed.</li>
|
|
<li>A finalizer is called exactly once, at the latest when the heap is
|
|
destroyed, unless the object is rescued by making it reachable again.
|
|
An object may be rescued by its own finalizer, or by another object's
|
|
finalizer when mark-and-sweep finalizes a set of objects. For example,
|
|
if <code>X.ref = Y</code>, and both X and Y become unreachable, it's
|
|
possible for Y's finalizer to run, and later on X's finalizer to rescue
|
|
both X and Y.</li>
|
|
<li>An object may be rescued an arbitrary number of times; the finalizer
|
|
is called exactly once for each "rescue cycle". Even with this
|
|
guarantee in place, it's best practice for a finalizer to be re-entrant
|
|
and carefully avoid e.g. freeing a native resource multiple times if
|
|
re-entered.</li>
|
|
<li>A finalizer is not executed for a Proxy object, but is executed for
|
|
the plain target object. This ensures that a finalizer isn't executed
|
|
multiple times when Proxy objects are created.</li>
|
|
</ul>
|
|
|
|
<p>Together these guarantee that a finalizer gets executed at some point
|
|
before a heap is destroyed, which allows native resources (such as sockets
|
|
and files) to be freed reliably. There are a few exceptions to this guarantee,
|
|
see below for more discussion:</p>
|
|
<ul>
|
|
<li>Heap destruction finalizer sanity limit may cause a finalizer not to
|
|
be executed.</li>
|
|
<li>When a script timeout is being propagated out of the current callstack,
|
|
ECMAScript finalizers will immediately rethrow the script timeout error.
|
|
Duktape/C finalizers will execute normally.</li>
|
|
<li>If Duktape runs out of memory (despite emergency GC) when trying to call a
|
|
finalizer, the call error is silently ignored and the finalizer will be
|
|
skipped.</li>
|
|
<li>When an object is finalized by mark-and-sweep but becomes unreachable
|
|
before the next mark-and-sweep round has a change to detect the rescue,
|
|
the object's finalizer will not be executed.</li>
|
|
</ul>
|
|
|
|
<p>When the Duktape heap is being destroyed there are a few limitations for
|
|
finalizer behavior:</p>
|
|
<ul>
|
|
<li>Finalizers are executed for all finalizable objects in the heap,
|
|
including reachable objects.</li>
|
|
<li>Finalizers cannot rescue objects; the semantics for a "rescue" would be
|
|
ambiguous. The finalizer's second argument is <code>true</code> when
|
|
called during heap destruction to indicate rescue is not possible.</li>
|
|
<li>A finalizer can create new finalizable objects and these objects will also
|
|
be finalized. For example, a finalizer may post a HTTP notification of
|
|
an object destruction which may use native network resources with their
|
|
own finalizers. However, there's a sanity limit to this process to ensure
|
|
runaway finalizers cannot prevent a heap from being destroyed.</li>
|
|
<li>The finalizer sanity algorithm is version specific, see
|
|
<a href="http://wiki.duktape.org/HowtoFinalization.html">How to use finalization</a>.
|
|
The algorithm allows the number of finalizable objects to grow initially,
|
|
but it must decrease in a reasonable time or the finalization process is
|
|
aborted, which may cause some native resource leaks.</li>
|
|
</ul>
|
|
|
|
<h2>Other current limitations</h2>
|
|
|
|
<ul>
|
|
<li>When script execution timeout
|
|
(<code>DUK_USE_EXEC_TIMEOUT_CHECK</code>)
|
|
is used and a timeout occurs, it's possible for an ECMAScript finalizer to start
|
|
running but immediately fail due to a script timeout. If this is a concrete
|
|
concern, use a Duktape/C native finalizer instead which will run normally even
|
|
when propagating a timeout.</li>
|
|
<li>The context (Duktape thread) executing the finalizer can currently be any
|
|
coroutine in the heap. This must be taken into account in sandboxing.</li>
|
|
<li>Finalizers cannot currently yield.</li>
|
|
</ul>
|
|
|