Тупит сборщик мусора

136
08 января 2020, 16:00

Чтобы было меньше вопросов, опишу краткую суть - Занимаюсь самописным модулем, он делает следующее: Получает небольшие данные буфером -> индексирует их -> на время кеширует -> и сохраняет на диск. Попутно сжимает их с помощью родного Zlib.gzip.

Но возникает гигантская проблема: пока идёт тестовый поток данных (6 мб/с - на что хватает ЦП) Zlib.gzip создаёт видимо столько мусора, что Сборщик запускается 4-6 раз в секунду. (скрин ↓↓↓)

И всё бы нечего, если бы объектов было мало но: чем больше становится объектов в памяти, тем дольше работает Сборщик каждый вызов и получается вот такая бредо-ситуация после добавления 2 миллионов балластных объектов. Сборщик работает Часто и по Долгу съедая 80% CPU от всего скрипта. (скрин ↓↓↓)

При чём когда сжатие не использую, и используя тот же балласт, Сборщик работает редко и Быстро. То есть балласт попросту не отражается на работе.

Еще также отмечу, что сильных колебаний в расходе памяти нет, и Сборщик срабатывает на незначительные кусочки мусора на фоне используемой Кучи в 500Мб (включая балласт).

Учитывая что из за индексации кол-во объектов спокойно переваливает за 100К, то проблема со Сборкой мусора стоит очень остро, и я не понимаю как эту проблему можно побороть. Есть какая либо возможность помочь Сборщику не тупить? (не особо разбираюсь в параметрах движка v8)

Мне слабо верится в то, что родной модуль Zlib - криво написан, и что он вызывает такие проблемы.

(кстати --max-semi-space-size и --max-old-space-size не влияют) (Мусор обычно подавляюще состоит из буферов) (NodeJS v11.13)

Answer 1

Спустя некоторое время изрядных поисков информации и тестов, пришел к заключению: (Конечно на все 100% заверять не могу в верности вывода, ибо в исходниках я не копался.)

Опуская подробности: Сборщик явно не дружит с буферами, и когда срабатывает тригер сборки при выделение памяти, начинает работать исключительно глобальная сборка мусора (Mark-sweep), к примеру поток создания буферов в 50 мб/с приводит к примерно ежесекундному запуску глобального Сборщика, при учёте того, что даже если нечего очищать в Старой памяти (устанавливая параметр на счётчик выживания = 10+ и не создавая ссылок что либо, не создавая жизни вне рамок жизни функции - явно демонстрирует это).

В моём же случае вызывание по 4-6 раз в секунду Сборщика вызвало излишнее выделение памяти, к примеру от сжатия с помощью Zlib - а он с буфером работает и буферами погоняет, дублируя входящий буфер при копировании памяти для работы в соседнем потоке. Но и еще не забывая про выделение памяти для буфера-результата.

То есть по моему мнению в этом аспекте - срабатывание алгоритма сборщика мусора работает не правильно - это как первый момент, второй момент в том - что нет каких либо настроек внешней памяти и её сборки, а ведь это не менее важные параметры как Old/Semi-memory-size так как имеют прямое отношение к алгоритму Сбора мусора. Была бы возможность в моём случае к примеру установить хотя бы даже лимит выделения внешней памяти между Сборками в 1 Гб, он бы уже бы снизил частоту вызовов Глобальной Сборки в 15-20 раз, и соответственно и нагрузка от неё тоже.

Если вдруг появится какая либо информация как побороть проблемное поведение GC, то постараюсь поделиться её здесь, и если у кого либо тоже она будет, буду признателен не только я, ибо я очень сомневаюсь, что только меня одолевает это.

============================== Дополнение =============================

Возвращаясь к этому вопросу, до тех пор пока буфера nodejs будут вызывать глобальную сборку мусора, можно лишь использовать заплатку в виде использования дополнительного потока из Worker Threads под хранение в памяти больших объектов или под всю работу с буферами от создания до удаления (а такое бывает нечасто возможным). В более сложных случаях остаётся лишь кардинальные меры в виде перекомпановки под себя самого nodejs или вообще использование другого языка.

READ ALSO
как можно переписать этот метод на async/await

как можно переписать этот метод на async/await

как можно переписать эту функцию без использования new Promise, используя только async/awaitМожет есть какие то примеры?

152
Создание сервера в nodejs

Создание сервера в nodejs

Изучаю nodejs, подскажите чем отличаются эти команды:

156
Условие для появления кнопки

Условие для появления кнопки

Всем привет, как то стрельнуло в голову, сделать простейшую тестовую игрулюЦель - перелистывать картинки нажатием кнопки или ссылки, + при...

115