Отслеживание утечки памяти в Ruby on Rails 3/Postgres/Apache Passenger application
Здравствуйте,
мы недавно обновили приложение к Rails 3.0.4 (3.0.5 на сервере онлайн-разработки). Большинство изменений с 2.3.10 до 3.0.4 были связаны с устаревшими или устаревшими плагинами и драгоценными камнями и были разрешимы с относительной легкостью. Но одна вещь заставляет меня сойти с ума:
Каждый отдельный веб-запрос в режиме разработки заставляет серверный процесс выделять около 50-60 МБ больше памяти, чем раньше. Эта память не освобождается после запроса, по крайней мере, не все. После 10-20 запросов каждый экземпляр Ruby потреблял более 500 МБ ОЗУ, в то время как наши предыдущие экземпляры Rails 2.3.10 редко превышали 200 МБ.
Это делает невозможным запуск наших 1300 тестов, потому что машина Devel 4GB RAM заполняется до конца тестов. Это происходит только в режиме разработки с cache_classes = false
. Если я переключу cache_classes на true, экземпляры Rails будут потреблять около 200 МБ памяти, а затем оставаться там. Однако во время тестов, даже с cache_classes = true, использование памяти будет расти.
Я запросил ObjectSpace и выяснил, что с каждым запросом около 3500 новых Proc, до 50 000 новых строк и 3000 новых хэшей и массивов создаются и не освобождаются. Эти строки (при сбрасывании) содержали весь мой исходный код, включая плагины и драгоценные камни, документацию, комментарии к исходному коду и имена путей. (Почему?)
Чтобы найти причину этого, вот что я пробовал: (После каждого изменения я забил приложения с помощью ab -n 50
.)
- Я создал новое приложение Rails 3 с единственным ресурсом и контроллером и SQLite3 DB. Использование памяти началось с 60 МБ и оставалось ниже 80 МБ.
- Я изменил "sqlite3" на "pg" и указал новое приложение Rails 3 на мою существующую базу данных Postgres. Использование памяти началось с 110 МБ и не превышало 130 МБ. (Боковой вопрос: почему камень Postgres использует гораздо больше памяти, чем драгоценный камень SQLite3?)
- Я скопировал мой Gemfile и Gemfile.lock из сломанного приложения Rails3 в приложение с голыми костями и выполнил установку пакета. Без изменений память оставалась примерно в 115 МБ, независимо от того, сколько запросов было сделано.
- Я создал пустой "def FooController", def foo; render: text = > "foo" end; end "в сломанном Rails3 приложении. Использование памяти росло медленнее, но по-прежнему не переставало расти после запросов.
- Я удалял каждый маршрут, кроме маршрута FooController. Без изменений.
- Я отключил все драгоценные камни, за исключением следующих:
pg, rails, aasm, will_paginate, geokit-rails3, koala, omniauth, paperclip
. Без изменений.
- Я отключил все 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 (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
Некоторые полезные ресурсы, которые помогут вам отслеживать источник утечек:
Новее:
Найти утечку памяти в проекте Ruby on Rails
Older:
ruby /ruby на обнаружении утечки памяти rails
http://tomcopeland.blogs.com/juniordeveloper/2007/09/tracking-down-a.html
http://xdotcommer.wordpress.com/2009/03/03/tracking-down-a-memory-leak-performance-issues-in-rails/