-
-
Notifications
You must be signed in to change notification settings - Fork 97
Memory leak when using Task#with_timeout #176
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
Comments
Hmm, thanks for reporting this, I'll take a look. |
#!/usr/bin/env ruby
require 'async'
require 'memory'
def consumer
Async do |task|
report = Memory.report do
1000000.times do
task.with_timeout(0.001) do
# no-op
rescue Async::TimeoutError
# no-op
end
end
end
report.print
binding.irb
end
end
task = consumer
task.wait Memory Profile
By Gem (288.00 MiB in 4000000 allocations)
By File (288.00 MiB in 4000000 allocations)
By Location (288.00 MiB in 4000000 allocations)
By Class (288.00 MiB in 4000000 allocations)
|
I see what is going on. In order to avoid scheduling timeouts which is expensive, we put them into a queue. Most timeouts are short lived and don't fire because the operation happens immediately. e.g.
most of the time, Basically, There is a However, if you have a tight loop, this queue can grow indefinitely. I think the solution is just to flush the queue after it gets to a certain size, probably 100 or 1000. The goal is to avoid adding a huge overhead, while also minimising the cost of inserting timers. |
I was starting to focus on
Which does seem to stabilise the memory usage but that may have more todo with the IO (which also seems to be required) |
Any time you context switch e.g. on IO, the timers queue is flushed. We just need to flush it more often. |
Thanks for the speedy assistance, @ioquatix! ❤️ Should we be adding the (I've been debugging our memory leak with @jpaulgs and @oeoeaio) |
I'm going to release an update to fix the issue in the timers gem. |
socketry/timers@1ec78fb is the initial attempt at a fix, without introducing too much overhead. To be honest, using a linked list here would make way more sense. My plan has always been to replace the timers gem with C implementation in This should avoid the worst case, but it won't avoid the case where you create lots of timers and interleave cancelled and non-cancelled timers. We could do more work in |
We have tested the changes to the timers gem and while they do appear to remove the accumulation of We've made an attempt to fix this issue in #186 |
Thanks for this update. |
The latest release should address the memory leaks. |
I am going to close this issue. Based on the reproduction scripts, the issue no longer exists. |
Hey, I'm running ruby 3.1.2 and version 2.0.3 of the Async rubygem. The code above is similar to what we are using. It exhibits a memory leak. The following photo was from running this for about 15 minutes, it certainly never releases the memory.
I'll keep digging to see what I can find out.
The text was updated successfully, but these errors were encountered: