-
Notifications
You must be signed in to change notification settings - Fork 2
Conversation
lib/living_dead.rb
Outdated
trace = ObjectTrace.new(*args) | ||
|
||
self.tracing_hash[trace.key] = trace | ||
self.freed_hash[trace.key] = false | ||
|
||
ObjectSpace.define_finalizer(args.first, -> (object_id) { LivingDead.freed_hash[object_id] = true }) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You need to write a method that generates the lambda. This lambda will capture the environment and hold a reference to args
, which I assume contains a reference to the object you want released?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good call. Related: would like to make a tool to make a context leak like this easier to find/debug if it's happening somewhere in a larger app. Working on a WeakRef
solution, which is yet another thing I didn't realize existed.
You might be able to simplify further by using a require 'weakref'
obj = Object.new
ref = WeakRef.new obj
p ref.weakref_alive? # => true
obj = nil
GC.start
p ref.weakref_alive? # => nil |
Or even require 'weakref'
class WeakRef
def collected?
!weakref_alive?
end
end
obj = Object.new
ref = WeakRef.new obj
p ref.collected? # => false
obj = nil
GC.start
p ref.collected? # => true |
Thanks again for pointing out both finalizers and weakref. This implementation with weakref works great. Actually with Unfortunately I'm still having the same problems with GC. Need to call it multiple times and need to call Also this isn't as bulletproof as the original C-extension. When I run the tests in a loop I eventually get a failure:
|
Actually scratch that comment about this being less bullet proof than master. I just got a failure there too:
So it seems that there is some kind of bug, some of the time, that prevents objects from being properly freed even with my weird |
I ported over schneems/heap_problem#1 to try to make this deterministic. It passes on my machine but fails on travis. I'm able to repro with the docker image locally. @matthewd any ideas on the difference here between mac and linux? Different stack size? Maybe it's different in a container? Here's the most recent commit 59cfa83 |
Instead of picking a magic number and we can create an object in memory that is not retained, we then trace the object and while we detect that it is in memory we repeatedly flush the stack and create new objects. Once the object is out of memory then we can determine that it’s been removed by GC. The theory here is that since the object we are tracing is more recent than the object that the user is tracing it will be more likely that GC will have cleared any unused objects before getting to the one we just created. It’s still not perfect, but hopefully it’s better than it was previously.
Got an idea talking with @olivierlacan and i've got a new implementation pushed to this branch d61fe4c The new idea is that we can be smarter about how many times we need to "flush" the stack by monitoring a known non-retained object. I'm still not 100% sure that this "solves" the problem, but it is light years beyond what I was doing. What do you think @matthewd @tenderlove @ko1 ? |
I don't believe that theory holds. If an object survives a plain Given that such a reference exists, the object's longevity is based on how long until that unused memory gets overwritten -- which has nothing to do with any other new objects that get created & destroyed in the meantime. AFAICS, your |
I was thinking that maybe the issue was incremental GC and not that something looked like a reference. But I guess I have no way of seeing if the object was unmarked or not unless I instrumented the GC code. |
Still not "solved" but i'm cleaning my PRs. It's better than what's in master, but I'm not using this anywhere. |
No description provided.