Trace what prevents an object from being GC'd?
-
Is there a way to trace back the references of an object in some manner? Finding the cause to why an object isn't garbage collected.
I've used ObjectSpace to inspect the count, where I've noticed some objects aren't GC'd. And after trying to set all references I know of to nil - they still aren't GC'd.
-
several solutions:
- patch ruby vm - https://gist.github.com/73674
- memproof gem - http://timetobleed.com/memprof-a-ruby-level-memory-profiler/ (Linux x64 only)
- ripping the internals via debugger - http://www.coffeepowered.net/2010/08/23/debugging-memory-leaks-in-ruby-with-gdb-round-2/
does it eat a lot memory ?
-
@unknownuser said:
does it eat a lot memory ?
theee... I don't have an overview of that. ...I know... don't optimize what doesn't need to be, but it bothers me that I don't know why.
It's a subclasses WebDialog, where a WebDialog will normally GC, my subclassed version doesn't. So everytime I create one, it lingers about. (how much memory usage, I'd expect depends on the HTML content.)
(another odd thing about WebDialogs, when I create one, a normal one, ObjectSpace's count increased by two...
-
@thomthom said:
(another odd thing about WebDialogs, when I create one, a normal one, ObjectSpace's count increased by two...
I remember AdamB posting about this in another thread last year (or so,)....
.. anyway. The "hidden" reference is held by the C++ as the object is a MFC window object (on PC,) and in ObjectiveC (on Mac,) as an NSWindow object.
-
It does occur to me that we do not have a call to tell the Sketchup C++ engine that we are done with a WebDialog instance and want it "disposed of".
We would need an
.dispose()
instance method for theUI::WebDialog
class, that would tell the C++ engine to get rid of it's reference (and then sets the receiver on the Ruby-side tonil
[if that's possible.])Then you can get rid of your class definition using
remove_const(:MyWebDialogSubclass)
-
The thing is, a normal WebDialog instance will be GC'd if you clear all references to it.
But there is something I have done in my subclass that prevents this - and I'm not finding out why..
-
@thomthom said:
The thing is, a normal WebDialog instance will be GC'd if you clear all references to it.
Sure.. as I remember Adam's post .. I thot he showed they were not GC'd.. but is was awhile back.
It could be nothing more exotic than that Google did not account for us subclassing
UI::WebDialog
, similar to the way some API methods only accept exact classes and not any subclasses. -
Did you dispose of all Locals, Constants, instance vars, and perhaps maybe even Procs that are within your subclass?
-
Maybe... I was planning on trying a simple subclass - without all the stuff I have in mine. Just to see if that makes the differences.
You could test the GC of a WebDialog if you like - so we can compare results.
I did a count of the existing WebDialogs, then created a new one. Made a new count ( +2 in my results ) then I set my references to the WD to nil and invoke GC.start. The count then went down by 2. Confirm?
-
@dan rathbun said:
Did you dispose of all Locals, Constants, instance vars, and perhaps maybe even Procs that are within your subclass?
I set all local variables to nil, nothing to the constants - just strings.
-
@thomthom said:
You could test the GC of a WebDialog if you like - so we can compare results. ... Confirm?
OK, here:
dlg = UI;;WebDialog.new >> #<UI;;WebDialog;0x61dc79c> ObjectSpace.each_object(UI;;WebDialog) {} >> 2 dlg=nil >> nil ObjectSpace.each_object(UI;;WebDialog) {} >> 2 GC.start >> nil ObjectSpace.each_object(UI;;WebDialog) {} >> 0 MyDialog = Class.new(UI;;WebDialog) >> MyDialog MyDialog.superclass >> UI;;WebDialog dlg=MyDialog.new >> #<MyDialog;0x6071ed4> ObjectSpace.each_object(UI;;WebDialog) {} >> 2 ObjectSpace.each_object(MyDialog) {} >> 2 dlg=nil >> nil ObjectSpace.each_object(MyDialog) {} >> 2 ObjectSpace.each_object(UI;;WebDialog) {} >> 2 GC.start >> nil ObjectSpace.each_object(MyDialog) {} >> 0 ObjectSpace.each_object(UI;;WebDialog) {} >> 0
-
But I did not
show()
the dialog in the previous test, so:dlg=MyDialog.new('Test') >> #<MyDialog;0x61d2f30> dlg.show >> true # empty dialog with title 'Test' is displayed, # .. and I close it manually. ObjectSpace.each_object(UI;;WebDialog) {} >> 2 ObjectSpace.each_object(MyDialog) {} >> 2 dlg=nil >> nil ObjectSpace.each_object(MyDialog) {} >> 2 ObjectSpace.each_object(UI;;WebDialog) {} >> 2 GC.start >> nil ObjectSpace.each_object(UI;;WebDialog) {} >> 0 ObjectSpace.each_object(MyDialog) {} >> 0
-
Are you testing on PC (v1.8.6-p287) or Mac (v1.8.5-p0) ??
I guess I should say that I'm running:
RUBY_VERSION 1.8.7 RUBY_PATCHLEVEL 299
.. get I set it for a test and forgot to set it back.
-
@ThomThom...
look at this example:
https://gist.github.com/355820A the bottom he determines that there is a finalizer that is holding a ref to the instance, and therefor the reason why the instance is not getting GC'd.
I know you were trying to use a finalizer to cleanup a temp file.. likely that's the culprit.
-
@dan rathbun said:
@ThomThom...
look at this example:
https://gist.github.com/355820A the bottom he determines that there is a finalizer that is holding a ref to the instance, and therefor the reason why the instance is not getting GC'd.
I know you were trying to use a finalizer to cleanup a temp file.. likely that's the culprit.
Not in this case. I'm testing on SU8, default Ruby. I've used finalizer, but it only triggers under OSX. And I've read the gotchas about finalizers not GC'ing - and implemented it so it doesn't hold a reference.
However, I think I'm somehow creating a reference somewhere... I just can't track it down...
-
It seems to be due to using
self.add_action_callback
within theinitialize
method of the subclass.<span class="syntaxdefault">class WC </span><span class="syntaxkeyword"><</span><span class="syntaxdefault"> UI</span><span class="syntaxkeyword">;;</span><span class="syntaxdefault">WebDialog</span><span class="syntaxkeyword">;</span><span class="syntaxdefault"> def initialize</span><span class="syntaxkeyword">(*</span><span class="syntaxdefault">args</span><span class="syntaxkeyword">);</span><span class="syntaxdefault"> super</span><span class="syntaxkeyword">;</span><span class="syntaxdefault"> self</span><span class="syntaxkeyword">.</span><span class="syntaxdefault">add_action_callback</span><span class="syntaxkeyword">(</span><span class="syntaxstring">'test'</span><span class="syntaxkeyword">)</span><span class="syntaxdefault"> </span><span class="syntaxkeyword">{</span><span class="syntaxdefault"> </span><span class="syntaxkeyword">|</span><span class="syntaxdefault">diag</span><span class="syntaxkeyword">,</span><span class="syntaxdefault">param</span><span class="syntaxkeyword">|</span><span class="syntaxdefault"> puts diag</span><span class="syntaxkeyword">,</span><span class="syntaxdefault"> param </span><span class="syntaxkeyword">};</span><span class="syntaxdefault">end</span><span class="syntaxkeyword">;</span><span class="syntaxdefault">end</span><span class="syntaxkeyword">;<br /></span><span class="syntaxdefault">nil<br /><br />ObjectSpace</span><span class="syntaxkeyword">.</span><span class="syntaxdefault">each_object</span><span class="syntaxkeyword">(</span><span class="syntaxdefault">WC</span><span class="syntaxkeyword">){}<br /></span><span class="syntaxdefault">0<br /><br />x</span><span class="syntaxkeyword">=</span><span class="syntaxdefault">WC</span><span class="syntaxkeyword">.</span><span class="syntaxdefault">new </span><span class="syntaxstring">'test'<br /></span><span class="syntaxcomment">#<WC;0x18dc1000><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">WC</span><span class="syntaxkeyword">){}<br /></span><span class="syntaxdefault">2<br /><br />x</span><span class="syntaxkeyword">=</span><span class="syntaxdefault">nil<br />nil<br /><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">WC</span><span class="syntaxkeyword">){}<br /></span><span class="syntaxdefault">2<br /></span>
When I use
add_action_callback
outsideinitialize
it does get GC'd.<span class="syntaxdefault">ObjectSpace</span><span class="syntaxkeyword">.</span><span class="syntaxdefault">each_object</span><span class="syntaxkeyword">(</span><span class="syntaxdefault">UI</span><span class="syntaxkeyword">;;</span><span class="syntaxdefault">WebDialog</span><span class="syntaxkeyword">){}<br /></span><span class="syntaxdefault">2<br /><br />wd</span><span class="syntaxkeyword">=</span><span class="syntaxdefault">UI</span><span class="syntaxkeyword">;;</span><span class="syntaxdefault">WebDialog</span><span class="syntaxkeyword">.</span><span class="syntaxdefault">new </span><span class="syntaxstring">'test'<br /></span><span class="syntaxcomment">#<UI;;WebDialog;0x18f1a2a8><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">UI</span><span class="syntaxkeyword">;;</span><span class="syntaxdefault">WebDialog</span><span class="syntaxkeyword">){}<br /></span><span class="syntaxdefault">4<br /><br />wd</span><span class="syntaxkeyword">.</span><span class="syntaxdefault">add_action_callback</span><span class="syntaxkeyword">(</span><span class="syntaxstring">'test'</span><span class="syntaxkeyword">)</span><span class="syntaxdefault"> </span><span class="syntaxkeyword">{</span><span class="syntaxdefault"> </span><span class="syntaxkeyword">|</span><span class="syntaxdefault">diag</span><span class="syntaxkeyword">,</span><span class="syntaxdefault">param</span><span class="syntaxkeyword">|</span><span class="syntaxdefault"> puts diag</span><span class="syntaxkeyword">,</span><span class="syntaxdefault"> param </span><span class="syntaxkeyword">}<br /></span><span class="syntaxdefault">true<br /><br />wd </span><span class="syntaxkeyword">=</span><span class="syntaxdefault"> nil<br />nil<br /><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">UI</span><span class="syntaxkeyword">;;</span><span class="syntaxdefault">WebDialog</span><span class="syntaxkeyword">){}<br /></span><span class="syntaxdefault">2<br /></span>
I don't understand why...
-
@thomthom said:
It seems to be due to using
self.add_action_callback
within theinitialize
method of the subclass.I don't understand why...
Oh.. that's an easy one: Because
**self**
IS a reference to THE instance.
So YOUR telling Ruby to keep 'literal' reference within the code.You dont need that reference by the way.. because the
initialize
method ALWAYS gets executed WITHIN the newly created instance, just after the class constructor (usuallynew
,) creates it.So just remove the "
self.
" from in front of ALL instance method calls made from within ANY of the object's instance methods. -
Interesting,
-
I had a suspicion that might be it, and it's what I had planned to try next. But I still don't understand why. As
self.add_action_callback
is just calling a method, never is self being stored in any reference... -
Removing
self.
fromadd_action_callback
made no difference.
Advertisement