An OutOfMemoryError occurs when an undefined method is invoked in a Rails 3.2 template, when the Rails app has many (15-30 resources) routes defined.
Instead of the Rails error expected in this case:
ActionView::Template::Error (undefined local variable or method `no_exist' for #<#<Class:0x1ad5686d>:0x30bad9de>)
there is a Java OutOfMemoryError:
=> Booting WEBrick
=> Rails 3.2.1 application starting in development on http://0.0.0.0:3000
=> Call with -d to detach
=> Ctrl-C to shutdown server
[2012-07-12 10:50:33] INFO WEBrick 1.3.1
[2012-07-12 10:50:33] INFO ruby 1.9.3 (2012-05-19) [java]
[2012-07-12 10:50:33] INFO WEBrick::HTTPServer#start: pid=6092 port=3000
Started GET "/bars" for 0:0:0:0:0:0:0:1 at 2012-07-12 10:52:44 -0400
Processing by BarsController#index as HTML
Rendered bars/index.html.erb within layouts/application (16115.0ms)
Completed 500 Internal Server Error in 16130ms
Java::JavaLang::OutOfMemoryError (Java heap space):
java.nio.HeapByteBuffer.<init>(HeapByteBuffer.java:57)
java.nio.ByteBuffer.allocate(ByteBuffer.java:331)
java.nio.charset.CharsetEncoder.encode(CharsetEncoder.java:792)
java.nio.charset.Charset.encode(Charset.java:846)
java.nio.charset.Charset.encode(Charset.java:869)
org.jruby.RubyEncoding.encode(RubyEncoding.java:178)
org.jruby.RubyString.<init>(RubyString.java:393)
org.jruby.RubyString.newString(RubyString.java:482)
org.jruby.Ruby.newString(Ruby.java:3086)
org.jruby.RubyBasicObject.hashyInspect(RubyBasicObject.java:1089)
org.jruby.RubyBasicObject.inspect(RubyBasicObject.java:1068)
org.jruby.RubyKernel.inspect(RubyKernel.java:1854)
org.jruby.RubyKernel$INVOKER$s$0$0$inspect.call(RubyKernel$INVOKER$s$0$0$inspect.gen)
org.jruby.RubyClass.finvoke(RubyClass.java:679)
org.jruby.javasupport.util.RuntimeHelpers.invoke(RuntimeHelpers.java:541)
org.jruby.RubyBasicObject.callMethod(RubyBasicObject.java:364)
org.jruby.RubyBasicObject.inspectObj(RubyBasicObject.java:1121)
org.jruby.RubyBasicObject.hashyInspect(RubyBasicObject.java:1089)
org.jruby.RubyBasicObject.inspect(RubyBasicObject.java:1068)
org.jruby.RubyKernel.inspect(RubyKernel.java:1854)
org.jruby.RubyKernel$INVOKER$s$0$0$inspect.call(RubyKernel$INVOKER$s$0$0$inspect.gen)
org.jruby.RubyClass.finvoke(RubyClass.java:679)
org.jruby.javasupport.util.RuntimeHelpers.invoke(RuntimeHelpers.java:541)
org.jruby.RubyBasicObject.callMethod(RubyBasicObject.java:364)
org.jruby.RubyObject.inspect(RubyObject.java:394)
org.jruby.RubyNameError$RubyNameErrorMessage.to_str(RubyNameError.java:120)
org.jruby.RubyNameError$RubyNameErrorMessage$INVOKER$i$0$0$to_str.call(RubyNameError$RubyNameErrorMessage$INVOKER$i$0$0$to_str.gen)
org.jruby.RubyClass.finvoke(RubyClass.java:679)
org.jruby.javasupport.util.RuntimeHelpers.invoke(RuntimeHelpers.java:541)
org.jruby.RubyBasicObject.callMethod(RubyBasicObject.java:364)
org.jruby.util.TypeConverter.convertToType(TypeConverter.java:71)
org.jruby.util.TypeConverter.convertToType(TypeConverter.java:117)
To reproduce this error, create a new Rails app and create a resource:
jruby -S rails new foo
jruby script\rails generate resource Bar
Add an action and in the view for the action, invoke an undefined method:
class BarsController < ApplicationController
def index
end
end
index.html.erb:
<% no_exist %>
Run with jruby script\rails server and access the page /bars should generate the expected Template Error page.
Now, add "resources" routes to config/routes.rb:
Foo::Application.routes.draw do
resources :bars
resources :cars
resources :things
resources :cups
resources :plates
resources :pads
resources :phones
resources :papers
resources :monitors
resources :books
resources :authors
resources :publishers
resources :subscribers
resources :readers
resources :buyers
resources :programs
resources :watches
resources :fingers
resources :hands
resources :thumbs
resources :speakers
resources :forks
resources :spoons
resources :pens
resources :pencils
resources :crayons
end
After adding 15-30 routes (seems to vary) the /bars page will generate an OutOfMemoryError instead.
Increasing the -Xmx doesn't fix the problem.
Changing the rails rescue handling in the template "render" method (actionpack-3.2.1\lib\action_view\template.rb) from:
...
view.send(method_name, locals, buffer, &block)
rescue Exception => e
handle_render_error(view, e)
end
to:
view.send(method_name, locals, buffer, &block) rescue nil
avoids the OutOfMemoryError, but of course without the Exception the error page cannot be rendered.
|