You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
(PUP-11755) Avoid slow, buggy pattern for enum functions
The each/filter/map functions, for some dispatches, use patterns that
are slow and/or buggy when run on jruby.
The correct pattern for enumeration is
```
object.each do |value|
yield(value)
end
```
Two alternatives in use are
```
enum = object.each
object.size.times do
yield(enum.next)
end
enum = object.each
begin
loop do
yield(enum.next)
end
rescue StopIteration
end
```
The first pattern is incorrect because it never triggers StopIteration
on the enumerator (by attempting to call `next` one last time). On MRI
this is apparently harmless, but on JRuby it leaves the Fiber associated with the
Enumerator around. Since Fibers are implemented via native threads on
JRuby, that leaves around a native thread. That can deplete the
available threads and interferes with garbage collection, as every
native thread functions as a GC root (leaving objects referenced but
functionally inaccessible).
The second pattern is technically correct but extremely inefficient on
JRuby, presumably due to the overhead associated with using a Fiber for
enumeration. It's also no more correct than simply calling the enum
method directly, so we can simply change it.
In benchmarks, the difference on MRI is ~10x and on JRuby it's ~150x.
0 commit comments