Отслеживание утечки памяти в Ruby on Rails 3 / Postgres / Apache Passenger - PullRequest
15 голосов
/ 20 марта 2011

Здравствуйте,

мы недавно обновили приложение до Rails 3.0.4 (3.0.5 на онлайн-сервере devel). Большинство изменений с 2.3.10 до 3.0.4 были вызваны устаревшими или устаревшими плагинами и драгоценными камнями и были решаемы с относительной легкостью. Но одна вещь сводит меня с ума:

Каждый отдельный веб-запрос в режиме разработки заставляет процесс сервера выделять примерно на 50-60 МБ больше памяти , чем раньше. Эта память не освобождается после запроса, по крайней мере, не все. После 10-20 запросов каждый экземпляр Ruby потреблял более 500 МБ ОЗУ , тогда как наши предыдущие экземпляры Rails 2.3.10 редко превышали 200 МБ.

Это делает невозможным выполнение наших 1300 тестов, потому что 4 ГБ оперативной памяти на машине devel заполнены до окончания тестов. Это происходит только в режиме разработки с cache_classes = false. Если я переключу cache_classes на true, экземпляры Rails будут занимать около 200 МБ памяти, а затем останутся там. Однако во время тестов, даже с cache_classes = true, использование памяти будет расти.

Я запросил ObjectSpace и обнаружил, что с каждым запросом создается около 3500 новых Proc, до 50 000 новых строк и 3000 новых хэшей и массивов, которые не освобождаются. Эти строки (при выгрузке) содержали весь мой исходный код, включая плагины и гемы, документацию, комментарии к исходному коду и имена путей. (Почему?)

Чтобы найти причину этого, я попробовал вот что: (После каждого изменения я забивал приложения ab -n 50.)

  1. Я создал свежее приложение Rails 3 с одним ресурсом и контроллером и БД SQLite3. Использование памяти началось с 60 МБ и осталось ниже 80 МБ .
  2. Я изменил 'sqlite3' на 'pg' и указал новое приложение Rails 3 на мою существующую базу данных Postgres. Использование памяти началось с 110 МБ и не превысило 130 МБ . (Дополнительный вопрос: почему гем Postgres использует намного больше памяти, чем гем SQLite3?)
  3. Я скопировал свои Gemfile и Gemfile.lock из сломанного приложения Rails3 в приложение "голые кости" и запустил пакетную установку . Без изменений , память оставалась на уровне около 115 МБ, независимо от того, сколько запросов было сделано.
  4. Я создал пустой "def FooController; def foo; render: text => 'foo' end; end" в сломанном приложении Rails3. Использование памяти росло медленнее, но оно все равно не прекращало расти после запросов .
  5. Я удалил все маршруты, кроме маршрута FooController. Без изменений .
  6. Я отключил все самоцветы, кроме следующих: pg, rails, aasm, will_paginate, geokit-rails3, koala, omniauth, paperclip. Без изменений .
  7. Я отключил каждый before_filter и after_filter в ApplicationController и каждый несущественный include в environment.rb. Я также синхронизировал boot.rb, environment.rb и application.rb с моим приложением Rails 3, за исключением пяти относительно простых наблюдателей, автоматически загружающих файлы в / lib и filter_parameters. Без изменений . Каждый новый запрос по-прежнему занимал дополнительные 10-50 МБ ОЗУ.

Если у вас есть представление о том, что здесь происходит, и где может быть утечка памяти, я был бы очень признателен за любую помощь. Я использую Rails 3.0.4 на OS X Snow Leopard, Rails 3.0.5 на Debian Lenny и

Спасибо!

Подойдя ближе:

Я удалил каждый плагин, каждый драгоценный камень, каждое расширение и все, что лично я не написал, так что мое приложение в основном голое. Особенно я удалил эти плагины: acts_as_list, acts_as_tree, asset_packager, forgot_password, fudge_form, fudge_scaffold, paperclippolymorph, query_trace, rails_upgrade, repeated_auto_complete-0.1.0, role_requirement, to_select, validates_url, and ym4r_gm.

Теперь мое приложение - все еще работает только вышеуказанный FooController! - начинается с 65 МБ и никогда не выходит за пределы 75 МБ ОЗУ, даже после того, как он набрал ab -n 1000 -c1 (1000 HTTP-запросов к / foo с использованием ApacheBench). К сожалению, без плагинов это также единственный URI, который работает вообще.

После некоторого копания кажется, что комбинация между плагинами Restful Authentication и Acts As State Machine (AASM) вызывает утечку памяти. См. Также https://github.com/Satish/restful-authentication/issues#issue/11. Я пока не уверен, почему, и простое включение «AASM» в мой «голый» проект само по себе не приводит к росту использования ОЗУ.

Я буду расследовать дальше.

Виновник найден

Это AASM. В Rails 3, похоже, утечка экземпляров объекта AASM :: xxx. см

Найден второй виновник

Произошла еще одна утечка памяти в rspec. Это сделало мои тесты почти невыносимо медленными, даже после удаления AASM, потому что две параллельно выполняющиеся задачи rspec (при использовании https://github.com/grosser/parallel_tests) в конце заняли почти 3 ГБ памяти. См. https://github.com/rspec/rspec-core/issues/#issue/321.

1 Ответ

2 голосов
/ 20 марта 2011
...