Using object ids to restore object instance references?
-
@myhand said:
Is there a reason I not just use the the material's
object_id.to_s()
as key and also as thumbnail file name etc. It seems unnecessary to concatenate with display_name and then hash, when object_id should be unique within one session...?I seem to have found the answer to this question the hard way... The
object_id
seem to expire after a while and I am getting "The object has been garbage collected" errors on a very large model when listing component definitions. It is all still in the same Sketchup session and all the component definitions are still in Sketchup, but somehow the id's you get fromComponentDefinition.object_id
can no longer be used to lookup those objects withObjectSpace._id2ref
.Does anyone know of a good key to use to uniquely reference Materials and ComponentDefinitions which can later (in the same Sketchup session) be used to reference them again. I could use
Entity.entityID
but then would have to iterate over all materials or component definitions to find the instance again. -
That's an interesting question I'd also like to know. Wasn't aware of ObjectSpace._id2ref .
Too bad that didn't work. Strange though, that it's garbage collected even when the entity exist. That would somewhat indicate that the Ruby object isn't permanently linked to the entity. I guess the Ruby object exist only for as long as there is a reference to it.(Might this be worthy of a separate topic for general discussion?)
-
hmm...
I tried to create a simple test case:
Get selected face:
face=sel[0]
Get its id:id = face.object_id
Dereference:face = nil
Trigger GC:GC.start
I'd then thought that I'd get the same error you got. But alas.
-
Here we go:
Sample model: A Face and four edges
<span class="syntaxdefault"><br />GC</span><span class="syntaxkeyword">.</span><span class="syntaxdefault">start<br />nil<br /><br />ObjectSpace</span><span class="syntaxkeyword">.</span><span class="syntaxdefault">each_object</span><span class="syntaxkeyword">(</span><span class="syntaxdefault">Sketchup</span><span class="syntaxkeyword">;;</span><span class="syntaxdefault">Edge</span><span class="syntaxkeyword">) { |</span><span class="syntaxdefault">e</span><span class="syntaxkeyword">| </span><span class="syntaxdefault">p e </span><span class="syntaxkeyword">}<br /></span><span class="syntaxdefault">0<br /></span>
Lets fetch the ID of each edge:
<span class="syntaxdefault"><br />ids </span><span class="syntaxkeyword">= </span><span class="syntaxdefault">model</span><span class="syntaxkeyword">.</span><span class="syntaxdefault">entities</span><span class="syntaxkeyword">.</span><span class="syntaxdefault">grep</span><span class="syntaxkeyword">(</span><span class="syntaxdefault">Sketchup</span><span class="syntaxkeyword">;;</span><span class="syntaxdefault">Edge</span><span class="syntaxkeyword">) { |</span><span class="syntaxdefault">e</span><span class="syntaxkeyword">| </span><span class="syntaxdefault">e</span><span class="syntaxkeyword">.</span><span class="syntaxdefault">object_id </span><span class="syntaxkeyword">}<br />[</span><span class="syntaxdefault">141734820</span><span class="syntaxkeyword">, </span><span class="syntaxdefault">141734790</span><span class="syntaxkeyword">, </span><span class="syntaxdefault">141404510</span><span class="syntaxkeyword">, </span><span class="syntaxdefault">141734760</span><span class="syntaxkeyword">]<br /> </span><span class="syntaxdefault"></span>
When we then inspect ObjectSpace:
<span class="syntaxdefault"><br />ids </span><span class="syntaxkeyword">= </span><span class="syntaxdefault">model</span><span class="syntaxkeyword">.</span><span class="syntaxdefault">entities</span><span class="syntaxkeyword">.</span><span class="syntaxdefault">grep</span><span class="syntaxkeyword">(</span><span class="syntaxdefault">Sketchup</span><span class="syntaxkeyword">;;</span><span class="syntaxdefault">Edge</span><span class="syntaxkeyword">) { |</span><span class="syntaxdefault">e</span><span class="syntaxkeyword">| </span><span class="syntaxdefault">e</span><span class="syntaxkeyword">.</span><span class="syntaxdefault">object_id </span><span class="syntaxkeyword">}<br /></span><span class="syntaxdefault">ObjectSpace</span><span class="syntaxkeyword">.</span><span class="syntaxdefault">each_object</span><span class="syntaxkeyword">(</span><span class="syntaxdefault">Sketchup</span><span class="syntaxkeyword">;;</span><span class="syntaxdefault">Edge</span><span class="syntaxkeyword">) { |</span><span class="syntaxdefault">e</span><span class="syntaxkeyword">| </span><span class="syntaxdefault">p e </span><span class="syntaxkeyword">}<br /></span><span class="syntaxcomment">#<Sketchup;;Edge;0x10db52bc><br />#<Sketchup;;Edge;0x10e566d0><br />#<Sketchup;;Edge;0x10e5670c><br />#<Sketchup;;Edge;0x10e56748><br /></span><span class="syntaxdefault">4<br /></span>
If we then trigger the GC:
<span class="syntaxdefault"><br />GC</span><span class="syntaxkeyword">.</span><span class="syntaxdefault">start<br />nil<br /><br />edges </span><span class="syntaxkeyword">= </span><span class="syntaxdefault">ids</span><span class="syntaxkeyword">.</span><span class="syntaxdefault">map </span><span class="syntaxkeyword">{ |</span><span class="syntaxdefault">id</span><span class="syntaxkeyword">| </span><span class="syntaxdefault">ObjectSpace</span><span class="syntaxkeyword">.</span><span class="syntaxdefault">_id2ref</span><span class="syntaxkeyword">(</span><span class="syntaxdefault">id</span><span class="syntaxkeyword">) }<br /></span><span class="syntaxdefault">Error</span><span class="syntaxkeyword">; </span><span class="syntaxcomment">#<RangeError; (eval);48;in `_id2ref'; 0x872b3a4 is recycled object><br /></span><span class="syntaxkeyword">(eval);</span><span class="syntaxdefault">48<br /></span><span class="syntaxkeyword">(eval);</span><span class="syntaxdefault">48<br /></span><span class="syntaxkeyword">(eval);</span><span class="syntaxdefault">48</span><span class="syntaxkeyword">;</span><span class="syntaxdefault">in </span><span class="syntaxkeyword">`</span><span class="syntaxstring">map'<br />(eval);48<br /></span>
Confirming my suspicion in my previous post.
Let then try to keep the references to each edge in an array:
<span class="syntaxdefault"><br />ids </span><span class="syntaxkeyword">= </span><span class="syntaxdefault">model</span><span class="syntaxkeyword">.</span><span class="syntaxdefault">entities</span><span class="syntaxkeyword">.</span><span class="syntaxdefault">grep</span><span class="syntaxkeyword">(</span><span class="syntaxdefault">Sketchup</span><span class="syntaxkeyword">;;</span><span class="syntaxdefault">Edge</span><span class="syntaxkeyword">) { |</span><span class="syntaxdefault">e</span><span class="syntaxkeyword">| </span><span class="syntaxdefault">e</span><span class="syntaxkeyword">.</span><span class="syntaxdefault">object_id </span><span class="syntaxkeyword">}<br />[</span><span class="syntaxdefault">141626980</span><span class="syntaxkeyword">, </span><span class="syntaxdefault">141626950</span><span class="syntaxkeyword">, </span><span class="syntaxdefault">141404510</span><span class="syntaxkeyword">, </span><span class="syntaxdefault">141626920</span><span class="syntaxkeyword">]<br /><br /></span><span class="syntaxdefault">edges </span><span class="syntaxkeyword">= </span><span class="syntaxdefault">ids</span><span class="syntaxkeyword">.</span><span class="syntaxdefault">map </span><span class="syntaxkeyword">{ |</span><span class="syntaxdefault">id</span><span class="syntaxkeyword">| </span><span class="syntaxdefault">ObjectSpace</span><span class="syntaxkeyword">.</span><span class="syntaxdefault">_id2ref</span><span class="syntaxkeyword">(</span><span class="syntaxdefault">id</span><span class="syntaxkeyword">) }<br />[</span><span class="syntaxcomment">#<Sketchup;;Edge;0x10e21cc8>, #<Sketchup;;Edge;0x10e21c8c>, #<Sketchup;;Edge;0x10db52bc>, #<Sketchup;;Edge;0x10e21c50>]<br /><br /></span><span class="syntaxdefault">GC</span><span class="syntaxkeyword">.</span><span class="syntaxdefault">start<br />nil<br /><br />edges </span><span class="syntaxkeyword">= </span><span class="syntaxdefault">ids</span><span class="syntaxkeyword">.</span><span class="syntaxdefault">map </span><span class="syntaxkeyword">{ |</span><span class="syntaxdefault">id</span><span class="syntaxkeyword">| </span><span class="syntaxdefault">ObjectSpace</span><span class="syntaxkeyword">.</span><span class="syntaxdefault">_id2ref</span><span class="syntaxkeyword">(</span><span class="syntaxdefault">id</span><span class="syntaxkeyword">) }<br />[</span><span class="syntaxcomment">#<Sketchup;;Edge;0x10e21cc8>, #<Sketchup;;Edge;0x10e21c8c>, #<Sketchup;;Edge;0x10db52bc>, #<Sketchup;;Edge;0x10e21c50>]<br /> </span><span class="syntaxdefault"></span>
Now the code worked - it survived the GC because we kept references to the Ruby objects pointing to the SketchUp entities.
Now sure how viable or even safe it would be to keep a cache of all the entities you keep an object ID of. If you did try so, you could even keep your own hash with object_id's as keys. But you'd have to ensure to check the entities if they are erased. Then further more there's the challenge that an entity is erased, but then restored after and undo/redo.
I see danger written all over this with memory leaks and stale references. -
Another observation:
<span class="syntaxdefault"><br />ids </span><span class="syntaxkeyword">= </span><span class="syntaxdefault">model</span><span class="syntaxkeyword">.</span><span class="syntaxdefault">entities</span><span class="syntaxkeyword">.</span><span class="syntaxdefault">grep</span><span class="syntaxkeyword">(</span><span class="syntaxdefault">Sketchup</span><span class="syntaxkeyword">;;</span><span class="syntaxdefault">Edge</span><span class="syntaxkeyword">) { |</span><span class="syntaxdefault">e</span><span class="syntaxkeyword">| </span><span class="syntaxdefault">e</span><span class="syntaxkeyword">.</span><span class="syntaxdefault">object_id </span><span class="syntaxkeyword">}<br />[</span><span class="syntaxdefault">139751680</span><span class="syntaxkeyword">, </span><span class="syntaxdefault">139751650</span><span class="syntaxkeyword">, </span><span class="syntaxdefault">139751630</span><span class="syntaxkeyword">, </span><span class="syntaxdefault">139751610</span><span class="syntaxkeyword">]<br /><br /></span><span class="syntaxdefault">ObjectSpace</span><span class="syntaxkeyword">.</span><span class="syntaxdefault">each_object</span><span class="syntaxkeyword">(</span><span class="syntaxdefault">Sketchup</span><span class="syntaxkeyword">;;</span><span class="syntaxdefault">Edge</span><span class="syntaxkeyword">) { |</span><span class="syntaxdefault">e</span><span class="syntaxkeyword">| </span><span class="syntaxdefault">p e </span><span class="syntaxkeyword">}<br /></span><span class="syntaxcomment">#<Sketchup;;Edge;0x10a8e174><br />#<Sketchup;;Edge;0x10a8e19c><br />#<Sketchup;;Edge;0x10a8e1c4><br />#<Sketchup;;Edge;0x10a8e200><br /></span><span class="syntaxdefault">4<br /><br />GC</span><span class="syntaxkeyword">.</span><span class="syntaxdefault">start<br /><br />new_ids </span><span class="syntaxkeyword">= </span><span class="syntaxdefault">model</span><span class="syntaxkeyword">.</span><span class="syntaxdefault">entities</span><span class="syntaxkeyword">.</span><span class="syntaxdefault">grep</span><span class="syntaxkeyword">(</span><span class="syntaxdefault">Sketchup</span><span class="syntaxkeyword">;;</span><span class="syntaxdefault">Edge</span><span class="syntaxkeyword">) { |</span><span class="syntaxdefault">e</span><span class="syntaxkeyword">| </span><span class="syntaxdefault">e</span><span class="syntaxkeyword">.</span><span class="syntaxdefault">object_id </span><span class="syntaxkeyword">}<br />[</span><span class="syntaxdefault">141455560</span><span class="syntaxkeyword">, </span><span class="syntaxdefault">141455530</span><span class="syntaxkeyword">, </span><span class="syntaxdefault">141455510</span><span class="syntaxkeyword">, </span><span class="syntaxdefault">141455490</span><span class="syntaxkeyword">]<br /><br /></span><span class="syntaxdefault">edges </span><span class="syntaxkeyword">= </span><span class="syntaxdefault">new_ids</span><span class="syntaxkeyword">.</span><span class="syntaxdefault">map </span><span class="syntaxkeyword">{ |</span><span class="syntaxdefault">id</span><span class="syntaxkeyword">| </span><span class="syntaxdefault">ObjectSpace</span><span class="syntaxkeyword">.</span><span class="syntaxdefault">_id2ref</span><span class="syntaxkeyword">(</span><span class="syntaxdefault">id</span><span class="syntaxkeyword">) }<br />[</span><span class="syntaxcomment">#<Sketchup;;Edge;0x10dce190>, #<Sketchup;;Edge;0x10dce154>, #<Sketchup;;Edge;0x10dce12c>, #<Sketchup;;Edge;0x10dce104>]<br /> </span><span class="syntaxdefault"></span>
Notice that after the Ruby object has been GC's and you then again request new references it's all new object instances.
It does seem like that SketchUp will ensure there is only ever one Ruby object per entity - so as long as anything is holding on to the reference to an entity SketchUp will reuse this. But once garbage collected it'll generate a new one when needed.
-
There are times when I wished I could extend just an instance reference to an entity, but I found that if I made changes to that instance, by adding a method or whatnot - it would also come over into any other plugin that referenced that entity.
Now I see that it's because SketchUp recycles the Ruby objects. Wish there was a way to decouple this - so I could get a unique ruby reference which I could mess with as much as I'd like.
-
@thomthom said:
Notice that after the Ruby object has been GC's and you then again request new references it's all new object instances.
It does seem like that SketchUp will ensure there is only ever one Ruby object per entity - so as long as anything is holding on to the reference to an entity SketchUp will reuse this. But once garbage collected it'll generate a new one when needed.
Very good detective work! Come to think of it I have seen similar behavior in JNI (Java Native Interface) where Java will garbage collect references to "proxy objects" when there are no longer java side references. This is because the C++ objects are not managed code running in a VM, and therefore Java does not have access the C++ object lifecycle (without custom hooks added on the C++ side).
-
Yea. Remember that the Ruby API was added in version 4 - it's on top of the C++ core in SketchUp.
Advertisement