New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Finalizers usage #1585
Comments
Also according to #473, finalizer are only run once. If this is the case, what's the point of adding the second argument |
Lots of questions, I'll try to cover them below. Finalizers execute when Duktape has determined that Duktape itself has no knowledge of a reference to the object. This may happen (almost) immediately if the object's reference count drops to zero, or with a significant delay if the object is in a reference loop and is reclaimed by mark-and-sweep. A finalizer can "rescue" an object by creating a reference visible to Duktape in the finalizer. When this is done, the finalizer will be executed again when the object becomes unreachable. However, if a finalizer would always rescue an object, even during heap destruction, the heap couldn't be destroyed because we'd just be running finalizers over and over again. So, there's a mechanism in heap destruction where Duktape eventually gives up and indicates heapDestruct=true, meaning that even if the finalizer rescues the object, the finalizer won't be called again. If your use case doesn't require object rescuing, you don't need to worry about any of that: you don't need to check heapDestruct. Just release any native resources and don't create a live reference (for Duktape) for the object being finalized. The best practice is still to make the finalizer robust re: native resources, e.g.: if (nativebuf) {
free(nativebuf);
/* set userdata to NULL to prevent double free, just in case */
} Note that "rescuing" is up to you - it doesn't happen by accident. |
Assuming TestObjs don't participate in reference loops, they should get their finalizers called (almost) immediately when they become unreachable. If that doesn't happen, there are two possibilities:
If the latter is true, calling duk_gc() would run the finalizers. Also voluntary periodic mark-and-sweep or mark-and-sweep triggered by out of memory will run the finalizers. |
That clears things out - I think it is the term "rescue" that confused me. At first I thought it is "automatically done" by the finalizer which employs some magical algorithm to determine that some objects is not ready for a death sentence. Maybe the wording in the doc:
can be changed to
|
I see what you mean, the "finalizer" here means the user finalizer code but it's indeed a bit ambiguous. I'll change the wording to be a bit more explicit. |
After reading the guide and the issues related to the finalizer I'm still quite confused with the usage of finalizers.
Example code is illustrated below.
Inside object constructor, I set finalizer to the object. It is a game engine I'm building so that inside each frame, many
TestObj
are created and manynativebuf
(of size 1000) are attached as "userdata" property. However, only until real heap_destruct will these objects (and native bindings) gets destroyed. This leads to out-of-memory very soon as heap is not destroyed until the game exited.I'm really confused as whether I should really be doing this or should I just free
nativebuf
regardless of the value ofheap_destruct
? The guide says that finalizers may "rescue" the objects - meaning that I shouldn't be freeingnativebuf
unconditionally. Is this true?The text was updated successfully, but these errors were encountered: