Оптимизация памяти
Сокращайте число выделений памяти
«Оптимизация памяти» — бесплатный урок Ruby Academy на CoddyKit. Это урок 3 из 4. Ты можешь прочитать весь урок бесплатно ниже — а потом практиковать его прямо в браузере с встроенным редактором кода и ИИ-репетитором 24/7. Это часть пути обучения Ruby Academy, и твой прогресс синхронизируется между веб-версией и приложением CoddyKit. Курс Ruby Academy содержит 4 уроков всего.
Почему важна память
Каждый создаваемый Ruby объект расходует память и увеличивает нагрузку на сборщик мусора. Чем меньше выделений, тем быстрее и компактнее программы.
- Сборщик мусора приостанавливает выполнение, чтобы освободить объекты
- Большое количество выделений вызывает более частые запуски сборщика мусора
- Уменьшение количества выделений часто даёт наибольший выигрыш
before = GC.stat(:total_allocated_objects)
100.times { 'new string' + '!' }
after = GC.stat(:total_allocated_objects)
puts "Allocated: #{after - before} objects"Подсчёт выделений
GC.stat предоставляет счётчики выделений, разницу которых можно вычислить до и после выполнения блока.
:total_allocated_objectsпостоянно увеличивается- Вычтите значение до выполнения из значения после, чтобы измерить отдельный участок
def allocations
before = GC.stat(:total_allocated_objects)
yield
GC.stat(:total_allocated_objects) - before
end
puts allocations { Array.new(1000) { |i| i.to_s } }Замороженные строковые литералы
Повторяющиеся строковые литералы каждый раз выделяют память под новый объект. Их заморозка позволяет Ruby повторно использовать один неизменяемый экземпляр.
- Добавьте специальный комментарий в начало файла
- Или вызовите
.freezeдля отдельных литералов
# frozen_string_literal: true
s1 = 'hello'
s2 = 'hello'
puts s1.equal?(s2)Избегайте выделения памяти в циклах
Создание объектов внутри часто выполняемых циклов многократно увеличивает объём выделяемой памяти. Вынесите константы за пределы цикла.
- Создайте регулярные выражения, массивы и строки один раз
- Повторно используйте их на каждой итерации
PATTERN = /\d+/
def count_numbers(lines)
lines.count { |line| line.match?(PATTERN) }
end
puts count_numbers(['a1', 'bb', 'c3'])Изменяющие методы (с восклицательным знаком)
Методы без восклицательного знака возвращают новые объекты, а методы с восклицательным знаком изменяют объект на месте, экономя память.
map!,gsub!,sort!- Используйте их только тогда, когда безопасно изменять исходный объект
arr = [3, 1, 2]
arr.sort!
puts arr.inspect
s = 'hello world'
s.upcase!
puts sСимволы и строки в качестве ключей
Символы интернируются: один и тот же символ представлен одним общим объектом. Используйте их в качестве ключей хеша.
- Строковые ключи каждый раз выделяют память под новую строку
- Символы экономят память при повторных поисках
puts :name.equal?(:name)
puts 'name'.equal?('name')Ленивые перечислители
Цепочка из map и select создаёт промежуточные массивы. lazy обрабатывает элементы по одному.
- Промежуточные коллекции не выделяются
- Это особенно удобно для больших или бесконечных последовательностей
result = (1..Float::INFINITY).lazy
.select { |n| n.even? }
.map { |n| n * n }
.first(5)
puts result.inspectПотоковая обработка вместо загрузки
Чтение целого файла в память расточительно. Вместо этого обрабатывайте его потоково, строка за строкой.
each_lineобрабатывает по одной строке за раз- Постоянный объём памяти независимо от размера файла
text = "line1\nline2\nline3"
text.each_line do |line|
puts line.strip.upcase
endОбъединение строк
Построение строк с помощью + в цикле каждый раз выделяет память под новую строку. Используйте <<, чтобы добавлять данные на месте.
+создаёт новый объект<<изменяет существующий буфер
buffer = String.new
5.times { |i| buffer << "item#{i} " }
puts bufferПулы объектов и повторное использование
Повторно используйте ресурсоёмкие объекты вместо того, чтобы создавать их заново.
- Кэшируйте разобранные конфигурации или скомпилированные регулярные выражения
- Используйте константу или мемоизированное значение
def config
@config ||= { host: 'localhost', port: 4567 }
end
puts config.equal?(config)Вызов сборщика мусора для анализа
Вы можете изучить работу сборщика мусора, чтобы подтвердить улучшения.
GC.stat(:count)показывает, сколько раз запускался сборщик мусора- Меньшее количество запусков после оптимизации — хороший признак
start = GC.stat(:count)
50_000.times { |i| [i] }
puts "GC runs: #{GC.stat(:count) - start}"Быстрая проверка
Проверьте свои знания об оптимизации памяти.
Повторение
Вы научились оптимизировать память:
- Подсчитывать выделения памяти с помощью
GC.stat - Замораживать строковые литералы и повторно использовать объекты
- Предпочитать методы с восклицательным знаком и
<<, чтобы не создавать новые объекты - Использовать символы для ключей и ленивые перечислители для конвейеров
- Обрабатывать большие объёмы данных потоково вместо полной загрузки
Далее Вы разберёте распространённые узкие места производительности.
Часто задаваемые вопросы
Урок «Оптимизация памяти» бесплатный?
Да — полный текст урока «Оптимизация памяти» бесплатно доступен здесь в веб-версии. Чтобы практиковать его интерактивно (встроенный редактор кода и ИИ-репетитор 24/7) и разблокировать остальной курс Ruby Academy, подпишись на CoddyKit PRO. Курс Ruby Academy содержит 4 уроков всего.
Чему я научусь в уроке «Оптимизация памяти»?
Сокращайте число выделений памяти Ты практикуешь Ruby Academy с помощью реального кода, который запускаешь прямо в браузере, и ИИ-репетитор 24/7 отвечает на твои вопросы во время урока.
Нужен ли мне опыт, чтобы начать Ruby Academy?
Предыдущий опыт не требуется. Ruby Academy на CoddyKit структурирован для всех уровней — от новичков до продвинутых, поэтому ты можешь начать отсюда или с самого начала и учиться в своем темпе. Это урок 3 из 4.
Сколько времени занимает урок «Оптимизация памяти»?
Большинство уроков CoddyKit занимают около 5–10 минут. Каждый из них компактный и интерактивный, поэтому ты постоянно делаешь прогресс и продолжаешь с того же места в веб-версии и приложении.
Можно ли писать и запускать код в этом уроке Ruby Academy?
Да. Каждый урок Ruby Academy включает встроенный редактор кода, поэтому ты пишешь и запускаешь реальный код прямо в браузере и получаешь моментальную обратную связь от AI — локальная установка не требуется.
Все уроки этого курса
- Измерение производительности
- Инструменты профилирования
- Оптимизация памяти
- Распространённые узкие места