Skip to content
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

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

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

Comments

Projects
None yet
3 participants
@akiellor
Copy link
Contributor

akiellor commented Apr 18, 2013

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

This comment has been minimized.

Copy link
Contributor

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

This comment has been minimized.

Copy link
Contributor

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

This comment has been minimized.

Copy link
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

This comment has been minimized.

Copy link
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
You can’t perform that action at this time.