在 2015年6月1日星期一 UTC+8下午11:27:34,Boris Zbarsky写道:
Post by Boris ZbarskyPost by Second DatkeAs you can see, nodes are mortal, so PersistentRooted is passed, as
its documented to be used for objects that lives as long as the
program.
Where is that documented?
PersistentRooted should be used for objects that live as long as the
PersistentRooted and which can't affect the lifetime of the
PersistentRooted. I don't know whether that's the case in your
situation or not.
Basically, a PersistentRooted ensures the thing it points to survives GC
as long as the PersistentRooted object exists. It's appropriate in your
case if there can't be any backreferences from the data to your Node
(which does seem unlikely if the data is consumer-provided).
Post by Second DatkeHeap objects is another option provided in SpiderMonkey, but
I'm not very clear about what "heap" is
Heap<T> should be used for anything that's not PersistentRooted and
doesn't have stack lifetime.
Post by Second Datkeand it is said that heap objects needs to be traced manually
Right, that's what keeps them from being garbage collected while you're
still referencing them.
Post by Second Datkeso what does "Heap" and "trace" means here
"Heap" means "the thing that owns this is on the C heap, not the C
stack". "trace" means "tell the GC there is an edge from the thing that
has the Heap member to the thing the Heap is pointing to".
Post by Second DatkeIf I have many nodes, that is, many PersistentRooted or Heap, would it lead to slow
performance?
Past the fact that GC has to walk them all, no.
So here is a question for you. You said you have these "Node" objects.
Are they JS objects? Where inside them are you storing the "data" member?
Post by Second DatkeCurrently I used a workaround for it. I defined a "HandleValue
*data", initialize with UndefinedHandleValue, and "repoint" to a
RootedValue in setters
This sounds like you're basically leaving dangling pointers in your data
member, since you're pointing them at the stack and then letting the
stack unwind. Please don't do that.
-Boris
Thanks for your reply and explanation of these structures!
Post by Boris ZbarskyUse JS::PersistentRooted<T> for things that are alive until the process exits.
I have no idea about whether to trust it. But I also read the comments of
RootingAPI.h above the definition of PersistentRooted<T>, however I cannot
fully understand. As you said, PersistentRooted<T> ensures objects live as long
as the PersistentRooted<T> alive. But what if the PersistentRooted<T> is deleted?
Would it be treated as a common GC thing as other JS GC things?
Post by Boris ZbarskyAnd yes, what I want is just reference counting that shared among C++ and JS. I'll
demonstrate my idea more clearly: I have a C++ Node class, which can be accessed
from JS, and it has a JS data field, which can be accessed from both C++ and JS,
and I want it integrated in to the Node class as a field. It's value is assigned in JS
and as long as the Node is alive, whether the JS side holds any reference to the data
or not, the data would not be collected. But when the Node is deleted, if the data is
referenced by JS, it would also keep away from being collected.
In fact, the "Node" in my problem is actually C++ objects, which is wrapped and exposed
to JS with JS class. The data field acts very similar to a field of JS objects. The only difference
is that the C++ Nodes also hold a reference to its data.
What object is stored in the data is just free for scripts. If possible, I want it able to be undefined, numbers, strings, booleans, objects etc. Although the very most of time they
are objects, I just want to do it gracefully and more freedom for scripting. Please pay
attention that it is assigned in JS, such as
some_node.data = new AnimationNodeData();
But its lifetime is shared as soon as the assignment takes place.
A little digression. JS::Heap<T> should be traced, and how to trace it? I googled and
found this, is it correct?
http://stackoverflow.com/questions/27393732/how-to-create-handle-and-destroy-jsheapt-objects-in-spidermonkey
And why JS::Heap<T> is designed this way? What if it is traced, or "rooted"
as long as created?
What this answer
Besides, I also looked through the definition of JS::PersistentRooted<T>. It seems that
it just added itself to a global list of JSRuntime. How could it hold up, if there are many
PersistentRooted inside the list?
TBH, I'm sometimes generous about memory now. Since I'm just prototyping. If GC becomes
an impact it can just be delayed. But I want to ensure that there is no leak, and no dangling.
What's more, if the data holds a backreference to node, using JS::PersistentRooted<T> cause a leak. As it's said in the comment in JSRootingAPI.h, that's because the C++ object is
not collected. But in my case, the lifetime of Nodes is managed in C++, JS would only holds
a pointer, In fact nodes would never be collected in JS, but deleted in C++. So the
PersistentRooted is destroyed, when the node is destructed manually, on C++ side.
Thus I think it should not be a problem. It seems the data would not have such
a backreference, I'm just talking for this case.
Post by Boris ZbarskyThe only exception to this is if they are added as roots with the JS_Add<T>Root()
functions or JS::PersistentRooted class, but don't do this unless it's really necessary.
It seems JS::PersistentRooted<T> is not recommended. But what's the difference between
a JS::PersistentRooted<T> and a traced JS::Heap<T>?