Почему цифры использования памяти наблюдателя Erlang / Elixir не складываются? - PullRequest
0 голосов
/ 27 мая 2018

Я начинаю с Elixir и наблюдаю странное поведение при подключении к моему удаленному производственному узлу с использованием iex.

Как и на снимке экрана ниже, наблюдатель сообщает, что используется всего 92 МБ памяти.Однако при суммировании потребления памяти процессами, атомами, двоичными файлами, кодом и т. Д. Получается: ~ 69 МБ

Processes  19.00 MB
    Atoms   0.97 MB (969 kB)
 Binaries  13.00 MB
     Code  28.00 MB
      ETS   7.69 MB (7685 kB)
-------------------
    Total  68.66 MB

enter image description here

Итак, мой первый вопрос: откуда взялись эти дополнительные 23 МБ памяти?Я уверен, что это не просто проблема с отчетностью.Потому что, когда я смотрю на потребление памяти моего модуля Kubernetes, оно составляет ~ 102 МБ , что соответствует цифрам, которые показывает наблюдатель.

enter image description here

Единственное, о чем я могу думать, это то, что эти 23 МБ еще не были собраны сборщиком мусора.Мое предположение верно?Если так, прошло 6 часов с момента запуска этого контейнера.И я отслеживал потребление памяти с самого начала.Разве это не должно быть сборкой мусора к настоящему времени?

И второй вопрос: есть ли какие-нибудь настройки Erlang VM / Elixir, которые я могу сделать, чтобы оптимизировать использование памяти?

1 Ответ

0 голосов
/ 22 ноября 2018

Я также пытался решить проблемы, связанные с управлением памятью в приложениях OTP, и одним из инструментов, который был особенно полезен для меня, является библиотека, написанная Фредом Хебертом, под названием conconnection .Особенно модуль recon_alloc, который предоставляет очень полезную информацию об использовании памяти в виртуальной машине Erlang.

Недостающие мегабайты

Следующая цитата непосредственно взята из документации по функции recon_alloc:memory() иможет дать вам представление о том, что происходит:

Память, сообщаемая `selected ', должна приблизительно соответствовать тому, что сообщает ОС.Если это количество отличается с большим отрывом, это может быть признаком того, что кто-то выделяет память непосредственно в C, вне собственного распределителя Эрланга - большой предупредительный знак.В настоящее время существует три источника выделения памяти, которые не учитываются в этом значении: кэшированные сегменты в распределителе mseg, любая память, выделенная как супер-носитель, и небольшие фрагменты памяти, выделенные во время запуска до инициализации распределителей памяти.Также обратите внимание, что низкое использование памяти может быть признаком фрагментации в памяти, и в этом случае рекомендуется исследовать, какой конкретный распределитель виноват.

Так что я думаю, что дополнительные 23 МБ использования памяти могут бытьвызванные некоторыми нежелательными выделениями или, возможно, из-за фрагментации.


Тонкая настройка (с большой осторожностью /! \)

Что касается вашего второго вопроса, в Эрланге есть инструмент под названием erts_alloc , который также описывает ручную настройкураспределители памяти.Это может быть сделано путем передачи флагов командной строки в эмулятор, например:

erl +SOMEFLAG +SOMEOTHERFLAG

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

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

ПРИМЕЧАНИЕ: Дикий выстрел здесь, в темноте, и если вы не отвечаете на ваш вопрос напрямую, но может быть полезно дважды проверить, что происходит с вашими двоичными файлами, так как я вижу, что их 13МБ сообщил наблюдатель.В зависимости от их размера (меньше или больше, чем 64 байта), они хранятся в кучах процессов или доступны по ссылке.Я столкнулся со случаем # 1 с множеством маленьких двоичных файлов, которые в конечном итоге приводили к краху моей системы.


Есть несколько других полезных ресурсов, которые я нашел, пытаясь решить эти проблемы:

  • Этот конкретный фрагмент из сообщения в блоге , автором которого является ФредХеберт, а также:

[erlang:garbage_collect(Pid) || Pid <- processes()].

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

[erlang:garbage_collect(Pid, [{async, RequestId}]) || Pid <- processes()].

  • This статья о GC в Erlang
  • Рекомендации по эффективности в Документах Erlang для двоичных файлов, которые предоставляют полезные подробности реализации.
  • Вещи идут плохо:Erlang in Anger , еще одна бесплатная электронная книга, написанная ... да, это Фред Хеберт.

Надеюсь, это поможет:)

...