Здравствуйте,
мы недавно обновили приложение до 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
.)
- Я создал свежее приложение Rails 3 с одним ресурсом и контроллером и БД SQLite3. Использование памяти началось с 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 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.