rails: Possible memory leak in prepend_view_path

I think I’m seeing a memory leak when using prepend_view_path.

When I use the instance method in a controller:

def setup_view_paths
  prepend_view_path(magazine_views)
end

I get a lot of leaked strings (and other objects in the same area)

Leaked 1384 STRING objects at: /Users/r38y/.rbenv/versions/2.1.1/lib/ruby/gems/2.1.0/gems/actionpack-4.0.2/lib/action_view/template.rb:299
Leaked 692 DATA objects at: /Users/r38y/.rbenv/versions/2.1.1/lib/ruby/gems/2.1.0/gems/actionpack-4.0.2/lib/action_view/template.rb:299
Leaked 616 ARRAY objects at: /Users/r38y/.rbenv/versions/2.1.1/lib/ruby/gems/2.1.0/gems/actionpack-4.0.2/lib/action_view/template.rb:299
Leaked 396 ARRAY objects at: /Users/r38y/.rbenv/versions/2.1.1/lib/ruby/gems/2.1.0/gems/actionpack-4.0.2/lib/action_view/template.rb:300
Leaked 395 DATA objects at: /Users/r38y/.rbenv/versions/2.1.1/lib/ruby/gems/2.1.0/gems/actionpack-4.0.2/lib/action_view/template.rb:106
Leaked 235 STRING objects at: /Users/r38y/.rbenv/versions/2.1.1/lib/ruby/gems/2.1.0/gems/actionpack-4.0.2/lib/action_view/template.rb:332
Leaked 197 NODE objects at: /Users/r38y/.rbenv/versions/2.1.1/lib/ruby/gems/2.1.0/gems/actionpack-4.0.2/lib/action_view/template.rb:299

That look like _app_views_site_overrides_j____com_posts_shared__featured_html_erb___3233500999093705389_70234272758740.

When I use the class method in an initializer:

ActionController::Base.prepend_view_path('app/views/site_overrides/j-14.com')

I don’t leak anything in template.rb.

I need to use the instance method because I need to set things up for themes.

I’ve seen this in production and development.

This is how I’m getting that information: https://gist.github.com/r38y/02f4378a19f9064d2da2

I’ve been in the Rails source code for a couple days and cannot figure out why it is leaking 😦. Any ideas would would a ton. Thank you!

About this issue

  • Original URL
  • State: closed
  • Created 10 years ago
  • Reactions: 2
  • Comments: 23 (8 by maintainers)

Most upvoted comments

Still happens with Ruby 2.7 and Rails 6.0 (possibly worse in Rails 6 vs. 5). Per-request prepend_view_path causes memory use to slowly increase without bound. Removing that call made a dramatic difference in my app’s memory usage. It’s an old app (began on Rails 2) with some complicated view building, so perhaps there’s an interaction with something else I’m doing. memory

While using a persistent Resolver instance also fixed a memory leak for me, I would caution that it is causing issues when Action View caching is disabled (e.g. in development mode).

Whenever I update a template, I get an undefined method error with a cached template name (e.g. _app_views...) due to the cache inside the persistent Resolver not being cleared by Action View Cache Expiry which relies on ActionView::ViewPaths.all_view_paths which doesn’t contain view paths prepended only to the current request’s Lookup Context.

I’m not sure what the right thing to do in this case is other than only using a persistent Resolver when Action View caching is enabled (falling back to using a String or Pathname with prepend_view_path so that a new Resolver is created for every request but re-introduces the memory leak). Alternatively, one could forcibly call clear_cache on any persistent resolver as long as ActionView::Resolver.caching? is false, e.g.

SUBDOMAIN_SPECIFIC_TEMPLATES = {
  'subdomain1' => ActionView::OptimizedFileSystemResolver.new('app/views/subdomain1'),
  'subdomain2' => ActionView::OptimizedFileSystemResolver.new('app/views/subdomain2'),
  'subdomain3' => ActionView::OptimizedFileSystemResolver.new('app/views/subdomain3')
}.freeze

def prepend_subdomain_specific_templates
  subdomain_specific_templates = SUBDOMAIN_SPECIFIC_TEMPLATES.fetch(request.subdomain)
  subdomain_specific_templates.clear_cache unless ActionView::Resolver.caching?

  prepend_view_path(subdomain_specific_templates)
end

Thanks for all this research. We also found this leak recently, and built a drop-in patch from the hints here and in this blog post.

Find our patch at https://makandracards.com/makandra/515345-rails-fixing-the-memory-leak-in-prepend_view_path.

Maybe related: https://github.com/rails/rails/issues/22580