Skip to content

Using Enumerable#cycle causes a background thread to be created but never destroyed. #647

Closed
akiellor opened this Issue Apr 18, 2013 · 4 comments

3 participants

@akiellor

Steps to reproduce.

Environment:
jruby 1.7.3 (1.9.3p385) 2013-02-21 dac429b on Java HotSpot(TM) 64-Bit Server VM 1.6.0_41-b02-445-11M4107 [darwin-x86_64]

  1. Start jvisualvm
  2. Start irb
  3. Attach jvisual vm to the irb process
  4. execute the following: > [1, 2].zip([3].cycle)
  5. Observe the RubyThread started from jruby/kernel/jruby/generator.rb still hanging around.
@nirvdrum
nirvdrum commented May 3, 2013

I can confirm this is an issue with master still, as of today. Here's the thread dump:

RubyThread-4: file:/home/nirvdrum/.rbenv/versions/jruby-1.7.4-dev/lib/jruby.jar!/jruby/kernel/jruby/generator.rb:125 [WAITING] CPU time: 0
java.lang.Object.wait(long, int)
org.jruby.RubyThread$SleepTask.run()
org.jruby.RubyThread.executeBlockingTask(RubyThread$BlockingTask)
org.jruby.RubyThread.wait_timeout(IRubyObject, Double)
org.jruby.ext.thread.SizedQueue.push(ThreadContext, IRubyObject)
org.jruby.ext.thread.SizedQueue$INVOKER$i$1$0$push.call(ThreadContext, IRubyObject, RubyModule, String, IRubyObject)
org.jruby.runtime.callsite.CachingCallSite.call(ThreadContext, IRubyObject, IRubyObject, IRubyObject)
org.jruby.ast.FCallOneArgNode.interpret(Ruby, ThreadContext, IRubyObject, Block)
org.jruby.ast.NewlineNode.interpret(Ruby, ThreadContext, IRubyObject, Block)
org.jruby.evaluator.ASTInterpreter.INTERPRET_BLOCK(Ruby, ThreadContext, String, int, Node, String, IRubyObject, Block)
org.jruby.runtime.Interpreted19Block.evalBlockBody(ThreadContext, Binding, IRubyObject)
org.jruby.runtime.Interpreted19Block.yield(ThreadContext, IRubyObject, Binding, Block$Type)
org.jruby.runtime.Block.yield(ThreadContext, IRubyObject)
org.jruby.RubyArray.cycleCommon(ThreadContext, long, Block)
org.jruby.RubyArray.cycle(ThreadContext, Block)
org.jruby.RubyArray$INVOKER$i$cycle.call(ThreadContext, IRubyObject, RubyModule, String, Block)
org.jruby.internal.runtime.methods.JavaMethod$JavaMethodZeroOrOneBlock.call(ThreadContext, IRubyObject, RubyModule, String, IRubyObject[], Block)
org.jruby.RubyClass.finvoke(ThreadContext, IRubyObject, String, IRubyObject[], Block)
org.jruby.runtime.Helpers.invoke(ThreadContext, IRubyObject, String, IRubyObject[], Block)
org.jruby.RubyBasicObject.callMethod(ThreadContext, String, IRubyObject[], Block)
org.jruby.RubyEnumerator.each(ThreadContext, Block)
org.jruby.RubyEnumerator.each(ThreadContext, IRubyObject[], Block)
org.jruby.RubyEnumerator$INVOKER$i$each.call(ThreadContext, IRubyObject, RubyModule, String, IRubyObject[], Block)
org.jruby.RubyClass.finvoke(ThreadContext, IRubyObject, String, IRubyObject[], Block)
org.jruby.runtime.Helpers.invoke(ThreadContext, IRubyObject, String, IRubyObject[], Block)
org.jruby.RubyBasicObject.callMethod(ThreadContext, String, IRubyObject[], Block)
org.jruby.RubyEnumerator.each(ThreadContext, Block)
org.jruby.RubyEnumerator$INVOKER$i$each.call(ThreadContext, IRubyObject, RubyModule, String, Block)
org.jruby.runtime.callsite.CachingCallSite.cacheAndCall(IRubyObject, RubyClass, Block, ThreadContext, IRubyObject)
org.jruby.runtime.callsite.CachingCallSite.callBlock(ThreadContext, IRubyObject, IRubyObject, Block)
org.jruby.runtime.callsite.CachingCallSite.callIter(ThreadContext, IRubyObject, IRubyObject, Block)
org.jruby.ast.CallNoArgBlockNode.interpret(Ruby, ThreadContext, IRubyObject, Block)
org.jruby.ast.NewlineNode.interpret(Ruby, ThreadContext, IRubyObject, Block)
org.jruby.evaluator.ASTInterpreter.INTERPRET_BLOCK(Ruby, ThreadContext, String, int, Node, String, IRubyObject, Block)
org.jruby.runtime.Interpreted19Block.evalBlockBody(ThreadContext, Binding, IRubyObject)
org.jruby.runtime.Interpreted19Block.yield(ThreadContext, IRubyObject, Binding, Block$Type)
org.jruby.runtime.Interpreted19Block.yieldSpecific(ThreadContext, IRubyObject, Binding, Block$Type)
org.jruby.runtime.Block.yieldSpecific(ThreadContext, IRubyObject)
org.jruby.ast.YieldOneNode.interpret(Ruby, ThreadContext, IRubyObject, Block)
org.jruby.ast.NewlineNode.interpret(Ruby, ThreadContext, IRubyObject, Block)
org.jruby.ast.RescueNode.executeBody(Ruby, ThreadContext, IRubyObject, Block)
org.jruby.ast.RescueNode.interpret(Ruby, ThreadContext, IRubyObject, Block)
org.jruby.ast.EnsureNode.interpret(Ruby, ThreadContext, IRubyObject, Block)
org.jruby.ast.BeginNode.interpret(Ruby, ThreadContext, IRubyObject, Block)
org.jruby.ast.NewlineNode.interpret(Ruby, ThreadContext, IRubyObject, Block)
org.jruby.evaluator.ASTInterpreter.INTERPRET_BLOCK(Ruby, ThreadContext, String, int, Node, String, IRubyObject, Block)
org.jruby.runtime.Interpreted19Block.evalBlockBody(ThreadContext, Binding, IRubyObject)
org.jruby.runtime.Interpreted19Block.yield(ThreadContext, IRubyObject, IRubyObject, RubyModule, boolean, Binding, Block$Type, Block)
org.jruby.runtime.Interpreted19Block.call(ThreadContext, IRubyObject[], Binding, Block$Type, Block)
org.jruby.runtime.Block.call(ThreadContext, IRubyObject[], Block)
org.jruby.RubyProc.call(ThreadContext, IRubyObject[], IRubyObject, Block)
org.jruby.RubyProc.call(ThreadContext, IRubyObject[])
org.jruby.internal.runtime.RubyRunnable.run()
java.lang.Thread.run()
@nirvdrum
nirvdrum commented May 3, 2013

I'm pretty confused by this one because the path it's going down in JRuby is as if a block were provided, but as can be seen in the Ruby snippet, there is no block for the cycle call.

@headius
JRuby Team member
headius commented May 3, 2013

Ok, this is pretty serious. Must be fixed for 1.7.4.

It has been on my to-do list to rework the Enumerator#next stuff to build off Fibers so we share a code path; this might be the time to make that happen.

@headius
JRuby Team member
headius commented May 8, 2013

Fixed via several commits leading up to d3cf295. We still need to reimpl the "lightweight" generators, but we shouldn't leak threads anymore.

@headius headius closed this May 8, 2013
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Something went wrong with that request. Please try again.