Lighthouse has a new layout. Prefer the old one? Return to the old layout, and switch back any time from the link at the top of each page.

This project is archived and is in readonly mode.

Possible memory leak in Rails 3

#4183

I have come across a situation where if a page is loaded many times, the memory usage of the process keeps on going up until eventually it consumes all the memory on the server, and eventually falls over due to excessive swapping.

I have confirmed that this is most likely to be a Rails problem by reproducing the memory leak by creating a basic Rails skeleton app, adding a single model, a single action in its controller that is completely empty, and a single view for that action that again is completely empty, so ultimately an empty page is rendered.

Ultimately, even with this completely basic app, with enough page loads, the memory leak shows up and the memory usage just keeps going up. There are no AR queries being made or anything like that, it literally just renders a blank page.

This occurs when it is run in development mode. I have confirmed that the memory leak does not occur when running in production mode, or turning config.cache_classes on in development mode.

Reported by Phil Evans · March 15th, 2010 @ 06:26 PM

State: resolved
Milestone: 3.0.2
Assigned to: Yehuda Katz (wycats) Yehuda Katz (wycats)
Importance: High

Activity

  1. Marc Baumbach
    Marc Baumbach

    I've seen this problem as well. I've tried with both Mongrel and WEBrick and confirmed that enabling config.cache_classes resolves the problem in development mode. Without it, the ruby process consumes about 2MB of memory every request without releasing the memory, although that number is likely application/request dependent.

    An easy way to reproduce it is to run a periodical updater from prototype for a little while. I ran an updater every 10 seconds and in less than an hour, my machine was becoming unresponsive and the server was completely unusable due to consuming so much memory.

    March 20th, 2010 @ 08:52 PM

  2. VirtualFunction
    VirtualFunction

    Ditto, I have this problem. I'm running from a recently compiled 1.9.x trunk and have this.

    In case others watch this, I would like to draw to peoples attention that Ruby x64 does have issues with it leaking memory in 1.8.7 and 1.9.1 when using include / extends (http://redmine.ruby-lang.org/issues/show/1392) which in some cases might give similar effects (though it's easy to tell as the Ruby bug also leaks in production, typically because most association proxy modules use 'extends' semantics).

    March 25th, 2010 @ 04:46 AM

  3. Marc Baumbach
    Marc Baumbach

    I guess to give a more concrete idea of my environment: I'm running Mac OS X Snow Leopard (latest updates) and Ruby 1.8.7.

    March 25th, 2010 @ 05:51 AM

  4. Rizwan Reza
    Rizwan Reza
    • Milestone cleared.
    • State changed from new to open

    I will inform Yehuda about this. Thanks for a good catch.

    March 25th, 2010 @ 05:16 PM

  5. Jeremy Kemper
    Jeremy Kemper
    • Assigned user set to Yehuda Katz (wycats)

    March 25th, 2010 @ 05:54 PM

  6. Yehuda Katz (wycats)
    Yehuda Katz (wycats)

    Are you running Rails master or Rails 3.0.0.beta?

    March 25th, 2010 @ 11:40 PM

  7. Marc Baumbach
    Marc Baumbach

    Not sure about everybody else, but I'm using Rails 3.0.0.beta.

    March 26th, 2010 @ 03:16 AM

  8. Phil Evans
    Phil Evans

    I am also using Rails 3.0.0.beta.

    March 26th, 2010 @ 09:40 AM

  9. José Valim
    José Valim

    I was not able to reproduce on master. If you guys can, please let us know.

    March 26th, 2010 @ 11:35 AM

  10. Rizwan Reza
    Rizwan Reza
    • Tag changed from memory leak, rails 3.0 beta to memory leak

    Can anyone confirm this on master? I am unable to reproduce this. Thanks.

    March 26th, 2010 @ 11:38 AM

  11. VirtualFunction
    VirtualFunction

    I've been using master for the last day and a bit, and it seems OK so far, no obvious leaks that I can see (though part of the reason I noticed this originally was a periodic AJAX call, which now seems to get cached as the development mode is now caching things that I've assigned page cache's to)

    March 26th, 2010 @ 02:52 PM

  12. José Valim
    José Valim
    • State changed from open to invalid

    Sweet! If you notice the issue again, I will reopen the ticket.

    March 26th, 2010 @ 11:01 PM

  13. Anthony Burns
    Anthony Burns

    I was still able to duplicate this error today using 1.9.1 and master. Happened during periodic AJAX calls, as well as with a continuous loop of requests to the root page of the app. However, setting config.cache_classes to true did fix the issue. I am on Ubuntu 9.10.

    March 31st, 2010 @ 05:46 PM

  14. ddelco
    ddelco

    I'm also seeing this error on 3.0.0.beta2, Ruby 1.8.7p248 on OS X. With config.cache_classes = false memory just balloons up with each request. Setting config.cache_classes = true looks like it resolves it.

    April 12th, 2010 @ 10:37 PM

  15. ddelco
    ddelco

    Also seeing this in master.

    April 13th, 2010 @ 03:24 AM

  16. iHiD
    iHiD

    I am seeing this on 3.0.0.beta2, Ruby 1.8.7p174 on Ubuntu.

    It occurs on both mongrel and webrick. Tried with "rackup" and "rails s".

    Thanks.

    April 27th, 2010 @ 10:38 AM

  17. iHiD
    iHiD

    This is fixed for me in edge as well. Thanks

    April 29th, 2010 @ 03:44 PM

  18. Nolan Meyers
    Nolan Meyers
    • Importance changed from to High

    I am still having this issue with 3.0.0.beta4 on either ruby-1.9.2-head or ruby-1.9.1-p378. As everyone else has noted, it only happens in development when config.cache_classes is disabled.

    June 28th, 2010 @ 08:58 PM

  19. Jeremy Kemper
    Jeremy Kemper
    • State changed from invalid to open

    June 28th, 2010 @ 09:43 PM

  20. Wijnand Wiersma
    Wijnand Wiersma

    I can confirm this. It seems to grow about 20Mb per request when running bundle exec rails s.
    Ruby version:
    ruby 1.8.7 (2009-06-08 patchlevel 173) [universal-darwin10.0]

    June 29th, 2010 @ 12:14 PM

  21. Wincent Colaiuta
    Wincent Colaiuta

    Another "me too". Seeing this with 3.0.0.beta4 on stock standard Mac OS X Snow Leopard Ruby (1.8.7), only in development mode (cache_classes = false).

    Start the server, real memory usage is 53.6MB. After the first 5 requests it's up to 100MB. Hammer the root path a 100 times with "ab" and it's up to 200MB. Basically it will swell up to consume as much real memory as the system will allow.

    So basically I am in the habit now of CTRL-C'ing and rerunning "rails server" every few dozen requests, because the machine just starts getting too slow.

    June 29th, 2010 @ 04:15 PM

  22. chaitanyav
    chaitanyav

    Can we use the hijack gem to get a irb session to the process and dump the object space to see what is taking up all the memory?. This can give us lot of information about what is taking up all the memory.

    June 29th, 2010 @ 05:32 PM

  23. Alex Le
    Alex Le

    I can confirm this memory leak behavior too. I'm using Rails 3 beta 4 with rvm's ruby 1.8.7 (ruby 1.8.7 (2010-01-10 patchlevel 249) [i686-darwin10.3.0]) and in development mode, the server keeps eating up more and more memory. I usually have to restart the server to get the memory usage under control again.

    June 30th, 2010 @ 01:22 AM

  24. beawesomeinstead
    beawesomeinstead

    +1

    I can confirm this on latest REE 1.8.7, Unicorn, Rails3 master as of today. Unicorn process is being SIGKILL-9'ed by kernel after few requests, because it starts to consume 100% cpu and 100% memory.

    June 30th, 2010 @ 05:49 AM

  25. chaitanyav
    chaitanyav

    Can someone please post sample app so that we can all reproduce the problem

    July 1st, 2010 @ 05:30 PM

  26. James Le Cuirot
    James Le Cuirot

    I take it no one has seen this in 2-3-stable? I witnessed some horrendous memory leaks today after updating Rails from 94878c61a329891eb904ace5b06dbc50831869d8 (around 2.3.6) to the latest from that branch. It actually ground our server to a halt so badly that I couldn't access it anymore. It's been fine since dropping back to the older code. I still need to investigate it further but I thought it was worth mentioning here.

    July 1st, 2010 @ 07:05 PM

  27. Jacob Coby
    Jacob Coby

    +1 here. I took an existing 2.3.8 app under development and upgraded to rails 3 beta4. I see an approximately 2mb memory leak every request with no upper limit. Reverting back to 2.3.8 fixes the problem.

    ruby 1.8.7 (2009-06-12 patchlevel 174) [universal-darwin10.0]

    I tried using hijack but it wasn't able to attach to the process.

    July 9th, 2010 @ 03:15 PM

  28. José Valim
    José Valim

    Could someone please publish an application on Github where the leak exists so someone can investigate?

    July 9th, 2010 @ 03:19 PM

  29. James Le Cuirot
    James Le Cuirot

    Ignore what I said, the 2-3-stable leak did not apply to master and has now been fixed.

    July 9th, 2010 @ 03:26 PM

  30. Thiago Moretto
    Thiago Moretto

    Same problem, 3.0.0.beta4, 1.8.7 on Snow Leopard in development mode. I tested a very simple Rails 3 application, requesting from browser and seems memory grow up, and never seems to lower. I booted another application with 2.3.8 and with same MRI 1.8.7 and no problems.
    See attached screenshot. The first process (5952) is the rails3 app and the second (6144) is the 2.3.8. Both using sqlite3 and in development mode.

    I have a another application that gets slower with time. But I can't share. I need to restart after some few minutes. With same configurations above.

    My tested rails3 app is here:
    http://github.com/thiagomoretto/agium

    How I can extract a memory dump to help?

    July 10th, 2010 @ 05:12 AM

  31. chaitanyav
    chaitanyav

    I was able to reproduce the issue, I ran the code @thiago posted on github. I looked at top output after the server was started, the res was 24m . After hitting the main page http://localhost:3000/ for 20-30 times continously. The res went to 27m.In the middle there was a internal server error, I captured the screenshot of the server output when the internal server error occured. Also attached a screenshot of my env. I will try to dump the object space using hijack and post my findings.

    July 10th, 2010 @ 06:54 AM

  32. Aman Gupta
    Aman Gupta

    @Thiago Thanks for the repro case. I was able to reproduce your leak (using rake db:migrate db:seed and then hitting http://localhost:3000/users repeatedly after adding some users) and track it down to AR validations. This leak has already been fixed in rails3 master and the fix will be included in rc1.

    July 26th, 2010 @ 06:50 PM

  33. Stephan Kaag
    Stephan Kaag

    Just curiosity: Aman can you specify the commit where this was fixed?

    July 26th, 2010 @ 07:18 PM

  34. iain
    iain

    Confirming that it has been fixed rc1: I tested a medium sized Rails 3.0.0.beta4 app with 'ab':

    0 requests: 94.2MB
    50 requests: 268.0MB
    100 requests: 320.8MB
    200 requests: 515.3MB
    300 requests: 695.9MB
    500 requests: 1.42GB

    And with ref:06b9531 (just moments before rc1 got released):

    0 requests: 94.5MB
    50 requests: 158.0MB
    100 requests: 156.2MB
    200 requests: 152.5MB
    300 requests: 155.5MB
    500 requests: 173.5MB
    1000 requests: 161.0MB

    Using ruby 1.8.7 (2010-04-19 patchlevel 253) [i686-darwin10.4.0], MBARI 0x6770, Ruby Enterprise Edition 2010.02

    July 26th, 2010 @ 11:06 PM

  35. Aman Gupta
    Aman Gupta

    @Stephan This commit fixed it: http://github.com/rails/rails/commit/b67ec8ba20099c8b39bf344f385bbb...

    Before this commit, all validations were added to ActiveRecord::Base._validators instead of the actual model classes themselves.

    ruby-1.8.7-p174 > ActiveRecord::Base._validators
     => {} 
    
    ruby-1.8.7-p174 > User
     => User(id: integer, login: string, password: string, admin: boolean, created_at: datetime, updated_at: datetime) 
    
    ruby-1.8.7-p174 > ActiveRecord::Base._validators
     => {:login=>[#<ActiveModel::Validations::PresenceValidator:0x104e7f220 @attributes=[:login, :password], @options={}>, #<ActiveRecord::Validations::UniquenessValidator:0x104e7b9e0 @attributes=[:login], @options={:case_sensitive=>true}, @klass=User(id: integer, login: string, password: string, admin: boolean, created_at: datetime, updated_at: datetime)>], :password=>[#<ActiveModel::Validations::PresenceValidator:0x104e7f220 @attributes=[:login, :password], @options={}>]}
    

    You can view the leak in more detail in the following heap dump: http://bit.ly/bn1EvM

    July 27th, 2010 @ 12:07 AM

  36. Jeremy Kemper
  37. Rizwan Reza
    Rizwan Reza
    • State changed from open to resolved

    September 6th, 2010 @ 10:41 PM

  38. Jeremy Kemper
  39. Jake Dempsey
    Jake Dempsey

    I am seeing this same problem. I have a rails 2.3.9 app that I converted to rails 3. Currently in development mode I see my ruby process grow by nearly 20mb on each request.

    I am running:

    OSX 10.6
    Rails 3.0.3
    REE ruby 1.8.7 (2010-04-19 patchlevel 253) [i686-darwin10.4.1], MBARI 0x6770, Ruby Enterprise Edition 2010.02

    Here are the numbers of my ruby process:
    0 Requests (just started app): 74.7mb
    1 Request: 76.2mb
    2 Request: 91.7mb
    3 Request: 110.7mb
    4 Request: 126.4mb
    5 Request: 144.5mb

    If i set config.cache_classes in dev mode to true:
    0 Request: 67.5mb
    1 Request: 69.5mb
    2 Request: 70.8mb
    3 Request: 72.1mb
    4 Request: 73.4mb
    5 Request: 74.1mb

    December 17th, 2010 @ 04:15 AM

  40. Jake Dempsey
    Jake Dempsey

    I found out what my issue was.. thought I would just reply here to show my findings

    I have created a small rails app here: https://github.com/angelo0000/memory_leak_test

    My problem is that I was requiring a file on my model from my lib dir:(MyLib which has a class level instance variable that is a Set of other classes). In one of my models I would add self to the MyLib class list (a way to do self registering for something) and the memory would just grow and grow. The issue was being caused because my model class was reloaded on each request but my MyLib class was not. When my model class loads, it then says MyLib.add(self) and self would be a new instance of the class on every request because of the class reloading.

    If I made no sense on the prev paragraph you can always just clone the git repo above and launch the rails app. If you go to the root url you should see the number of objects in MyLIb and the current memory footprint. Just hit refresh and you can see it grow. You can comment out the require in the user.rb, restart, and hit the root url again to see that only 1 object gets put in.

    December 17th, 2010 @ 06:46 AM

  41. VirtualFunction
    VirtualFunction

    @Jake...

    A lot of people don't realise, but you need to be very carefult if you are using class level variables or assigning any non primative type to a constant (If you do, I strongly suggest using .freeze to ensure you don't get memory leaks)

    Conversely, any class level variables that come are using in classes that get reloaded from the Rails dependency handler will often loose data between requests.

    For instance, if you do something like (trivial example):

    class Post < Activerecord::Base
    acts_as_tree @@root = root end

    could have some bad side effects in production because @@root doesn't get unloaded in production, and if this AR instance has loads of chilren non of the children ('i.e. @@root.children) will not get unloaded.

    You'll want to use freeze or stay away from complex data types for constants or class variables: e.g.

    class Post < Activerecord::Base
    acts_as_tree @@root = root.freeze end

    In the case of your repo code, the 'User class' will be a different object after each reload and like you say you get loads of objects in your set from all the different instances of User that get loaded. (You'll find in production it shouldn't leak, however I'd probably store strings and use a getter method that calls .contantize)

    December 17th, 2010 @ 10:35 AM

  42. Jake Dempsey
    Jake Dempsey

    @VirtualFunction

    I wasn't using class variables, but I agree with your observation. My main problem was with the User class reloading and when being added to my set, it was a different instance of that class so my Set really didnt work. I couldn't do a freeze because this is a registration mechanism that can actually occur at runtime. I just created that simple app to highlight my problem.

    I def agree with your observation about storing the the class name instead. I actually made that change last night after I realized what the problem was.

    December 17th, 2010 @ 02:26 PM

  43. José Valim
    José Valim

    Jake,

    Active Support provides a reference system since Rails 3. Here is an example from Devise:

    https://github.com/plataformatec/devise/blob/master/lib/devise.rb#L...

    It is just a reference and ensures it always point to the live object. Consequently you won't leak. I will write a blog post about it on Plataforma's blog later.

    December 17th, 2010 @ 02:36 PM

  44. stevo84
    stevo84

    I see it is resolved, but I still experience the same behaviour in development - and it quickly eats out my memory (around 40MB per request).

    ruby 1.8.7 (2010-04-19 patchlevel 253) [x86_64-linux], MBARI 0x6770, Ruby Enterprise Edition 2010.02
    Rails 3.0.3
    Ubuntu 10.10 (maverick) - kernel 2.6.35-24-generic

    January 27th, 2011 @ 08:33 AM

  45. Matt D
    Matt D

    I'm still dealing with memory leaks. I don't have many details now, since I'm just beginning to investigate, but I observed leaks with Ruby 1.9.2 on Rails 3.0.3 on a skeleton app :/ Will post when I find out more (and probably inevitably discover that it's my fault).

    February 2nd, 2011 @ 02:15 AM

  46. asoules (at gmail)
    asoules (at gmail)

    I'm having this problem in Rails 3.0.3 using Ruby 1.8.7 or 1.9.2. I've tried thin, mongrel, webrick, no luck there. config.cache_classes = true fixes the leak, but that's obviously less than ideal :)

    February 21st, 2011 @ 10:32 PM

  47. bingbing
  48. asoules (at gmail)
    asoules (at gmail)

    The leak that I am suffering from appears to be caused by AASM, not Rails. Check out the question posted by Jens on StackOverflow: http://stackoverflow.com/questions/5369623/tracing-memory-leak-in-r...

    April 8th, 2011 @ 04:54 PM