Каковы ваши стратегии, чтобы сохранить низкое использование памяти? - PullRequest
29 голосов
/ 28 сентября 2008

Ruby действительно требует много памяти, но также стоит каждого бита.

Что вы делаете, чтобы сохранить низкое использование памяти? Вы избегаете больших строк и вместо этого используете меньшие массивы / хэши, или это не проблема, чтобы заботиться о вас и позволить сборщику мусора выполнять свою работу?

Редактировать : Я нашел хорошую статью на эту тему здесь - старая, но все еще интересная.

Ответы [ 17 ]

9 голосов
/ 28 сентября 2008

Я обнаружил, что Phusion Ruby Enterprise Edition (ответвление от основной линии Ruby с значительно улучшенной сборкой мусора) существенно изменил использование памяти ... Кроме того, они сделали его чрезвычайно простым в установке (и удалении) , если вы обнаружите необходимость).

Вы можете узнать больше и загрузить его на на их сайте .

8 голосов
/ 28 сентября 2008

Я действительно не думаю, что это так важно. Делать ваш код менее читабельным, чтобы улучшить потребление памяти - это то, что вы должны делать только в том случае, если вам нужно . И по необходимости я имею в виду особый случай для профиля производительности и особые показатели , которые указывают, что любое изменение решит проблему.

Если у вас есть приложение, в котором ограничивающим фактором будет использование памяти, то Ruby может оказаться не лучшим выбором. Тем не менее, я обнаружил, что мои приложения Rails обычно потребляют около 40-60 МБ ОЗУ на экземпляр Mongrel. В плане вещей это не очень много.

Возможно, вы сможете запустить свое приложение на JVM с JRuby - виртуальная машина Ruby в настоящее время не настолько продвинута, как JVM для управления памятью и сбора мусора. В версии 1.9 добавлено много улучшений, а также разрабатываются альтернативные виртуальные машины.

6 голосов
/ 28 сентября 2008
  1. Выберите структуры дат, которые являются эффективными представлениями, хорошо масштабируются и делают то, что вам нужно.
  2. Используйте алгоритмы, которые работают с использованием эффективных структур данных, а не раздутых, но более простых.
  3. Посмотри еще где. В Ruby есть мост C, и в C гораздо проще ориентироваться в памяти, чем в Ruby.
6 голосов
/ 07 декабря 2012

Разработчикам Ruby очень повезло, поскольку им не нужно самим управлять памятью.

Помните, что ruby ​​выделяет объекты, например что-то простое, как

100.times{ 'foo' }

выделяет 100 строковых объектов (строки являются изменяемыми, и каждая версия требует отдельного выделения памяти).

Убедитесь, что если вы используете библиотеку, выделяющую много объектов, другие альтернативы недоступны, и ваш выбор стоит заплатить за сборщик мусора. (у вас может не быть много запросов / с или может не заботиться о нескольких десятках мс на запросы).

Создание хеш-объекта действительно выделяет больше, чем объект, например

{'joe' => 'male', 'jane' => 'female'}

выделяет не 1 объект, а 7. (один хеш, 4 строки + 2 строки ключей)

Если вы можете использовать символьные ключи, так как они не будут собирать мусор. Однако, поскольку они не будут собирать мусор, вы должны убедиться, что не используете полностью динамические ключи, такие как преобразование имени пользователя в символ, иначе вы «утечете» память.

Пример: Где-то в вашем приложении вы применяете to_sym к имени пользователя, например:

hash[current_user.name.to_sym] = something

Когда у вас есть сотни пользователей, это может быть хорошо, но что происходит, если у вас есть миллион пользователей? Вот цифры:

ruby-1.9.2-head >
# Current memory usage : 6608K
# Now, add one million randomly generated short symbols
ruby-1.9.2-head > 1000000.times { (Time.now.to_f.to_s).to_sym }

# Current memory usage : 153M, even after a Garbage collector run.

# Now, imagine if symbols are just 20x longer than that ?
ruby-1.9.2-head > 1000000.times { (Time.now.to_f.to_s * 20).to_sym }
# Current memory usage : 501M

Имейте в виду, что никогда не преобразовывайте неконтролируемые аргументы в символ или проверяйте аргументы ранее, это может легко привести к отказу в обслуживании.

Также не забывайте избегать вложенных циклов глубиной более трех уровней, поскольку это затрудняет обслуживание. Ограничение вложенности циклов и функций тремя уровнями или меньше - хорошее практическое правило для поддержания производительности кода.

Вот несколько ссылок относительно:

http://merbist.com

http://blog.monitis.com

4 голосов
/ 04 декабря 2012
  1. При развертывании веб-приложения Rails / Rack используйте REE или другой дружественный к копированию интерпретатор.
  2. Настройка сборщика мусора (см., Например, https://www.engineyard.com/blog/tuning-the-garbage-collector-with-ruby-1-9-2)
  3. Попробуйте сократить количество используемых вами внешних библиотек / гемов, поскольку дополнительный код использует память.
  4. Если у вас есть часть вашего приложения, которая действительно интенсивно использует память, возможно, стоит переписать ее в расширении C или дополнить ее, вызывая другие / более быстрые / лучше оптимизированные программы (если вам приходится обрабатывать большие объемы текстовых данных , может быть, вы можете заменить этот код вызовами grep, awk, sed и т. д.)
3 голосов
/ 28 сентября 2008

Я не разработчик ruby, но думаю, что некоторые приемы и методы верны для любого языка:

Используйте переменную минимального размера, подходящую для работы
Уничтожать и закрывать переменные и соединения, когда они не используются
Однако, если у вас есть объект, вам нужно будет использовать его много раз, чтобы сохранить его в области видимости. Любые циклы с манипуляциями с большой строкой приводят к работе с меньшей строкой и затем добавляются к большей строке

Используйте приличную (попробуйте перехватить наконец) обработку ошибок, чтобы убедиться, что объекты и соединения закрыты

При работе с наборами данных возвращайте только необходимый минимум

2 голосов
/ 28 сентября 2008

Взгляните на Программное обеспечение для малой памяти - шаблоны для систем с ограниченной памятью . Вы не указываете, какого рода ограничения памяти, но я предполагаю, RAM. Хотя это не относится к Ruby, я думаю, что вы найдете некоторые полезные идеи в этой книге - шаблоны охватывают ОЗУ, ПЗУ и вторичное хранилище и делятся на основные методы небольших структур данных, выделения памяти, сжатия, вторичного хранения и небольших архитектура.

2 голосов
/ 28 сентября 2008

За исключением случаев крайней необходимости, использование памяти не о чем беспокоиться. Время, которое вы потратите, пытаясь сократить использование памяти, купит LOT гигабайт.

2 голосов
/ 02 октября 2008

Избегайте кода, подобного этому:

str = ''
veryLargeArray.each do |foo|
  str += foo
  # but str << foo is fine (read update below)
end

, который создаст каждое промежуточное строковое значение как объект String и затем удалит его единственную ссылку на следующей итерации. Это переполняет память множеством длинных строк, которые нужно собирать.

Вместо этого используйте Array#join:

str = veryLargeArray.join('')

Это реализовано в C очень эффективно и не требует затрат на создание String.

ОБНОВЛЕНИЕ: Джонас прав в комментарии ниже. Мое предупреждение относится к +=, но не <<.

2 голосов
/ 29 сентября 2008

Единственное, что у нас когда-либо было, о чем стоило беспокоиться, это RMagick.

Решение состоит в том, чтобы убедиться, что вы используете RMagick версии 2, и позвоните Image#destroy!, когда вы закончите, используя свое изображение

...