Архитектура памяти: Erlang против Java

Автор оригинала: Byron (javacodegeeks.com)
  • Перевод
Я прочитал очень-очень интересную статью «Стратегии управления памятью для Erlang VM». Она была написана в качестве диссертации Джеспером Вильхельмсоном. Я подумал, что было бы неплохо обсудить различия между управлением памятью в Erlang и Java VM от Oracle.

Очень краткое введение для тех, кто никогда не слышал о Erlang: это функциональный язык, который использует асинхронную передачу сообщений в качестве основы для параллелизма. Для передачи сообщений используется семантика копирования, что делает, по существу, прозрачным для программиста распределение нескольких Erlang VM, работающих на более чем одной машине.

Erlang и Java похожи в в том смысле, что оба используют виртуальную машину для абстрагирования от аппаратного слоя. Оба языка используют машинно-независимый байт-код. Оба являются runtime-системами со «сборкой мусора», освобождающими программистов от ручного управления памятью.

Накладные расходы (в оригинале — overhead) для потоков в Erlang — очень низкие. Мне кажется, что для Erlang-потока требуется около 512 байт. Для Java-потоков, как правило, необходимо около 512 килобайт, что примерно в 1000 раз больше. Системы с множеством потоков, которые работают асинхронно должны быть хорошо продуманны программистом. Типичные Erlang-системы держат тысячи или десятки тысяч потоков. При этом никакого дураковаляния со threadpool'ами и executor'ами, которым мы занимаемся в Java.

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

Но этот пост не о модели программирования в Erlang. Он о том, как Erlang VM работает с памятью.

Виртуальная машина Java использует то, что Erlang программист назвал бы общей топологией кучи. Существует одна большая куча, которая используется всеми потоками. Большая часть памяти выделяется в этой куче. В дополнение к куче, JVM использует некоторые специализированные области данных, такие как кэш кода и permanent generation. Они также делятся между всеми потоками.

В отличие от этого, Erlang использует частные топологии кучи. Каждый поток имеет свою собственную крошечную кучу, которая содержит все данные, используемые потоком и его стек. Все данные потока находятся в его локальной куче. Она резервируется, когда создается поток. Когда поток уничтожается, вся куча просто возвращаются в пул свободной памяти.

Помимо частных куч, всем потокам доступна так называемая Бинарная куча и Куча сообщений. Это специализированные кучи. Бинарные кучи необходимы для выделения больших областей произвольных данных, которые могут быть разделены между потоками, например, входных файлов или сетевых буферов.

Куча сообщений предназначена для данных, используемых в сообщениях. Сообщения также распределяются между процессами. Сообщения передаются между потоками путем копирования указателя от потока-отправителя потоку-адресату. Данные же сообщения хранятся в Куче сообщений.

Я был впечатлен моделью памяти Erlang. Она кажется мне гораздо более масштабируемой, чем модель единственной кучи Java. Семантика языка и модель памяти Erlang прекрасно сочетаются.

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

В последней версии Erlang VM сделан еще один шаг вперед — возможность иметь более одного планировщика. Один планировщик на каждый физический процессор, если быть точным. Это также избавляет от проверок на целый класс блокировок. Когда планировщик простаивает, он может получить некоторые процессы от другого планировщика.

Java есть чему поучиться у Erlang. Тем не менее, есть несколько хороших вещей в Java, по которым я скучаю при работе с большими Erlang-системами.

Erlang VM будет перераспределять кучи, когда поток накапливает большое количество данных. Однако, при действии алгоритма перераспределения почему-то размеры кучи быстро растут. При высокой нагрузке, я видел, что Erlang VM съедает 16 Гб оперативной памяти в считанные минуты. Каждый релиз должен быть тщательно проверен в нагрузочном тестировании, чтобы он имел адекватные требования к памяти.

Пока нет механизмов в Erlang VM, позволяющих обуздать рост памяти. Виртуальная машина радостно выделяет так много памяти, что система бежит в своп и исчерпывает всю виртуальную память. Это может привести машину к «зависанию» даже при доступе через консоль KVM. В прошлом мы должны были перегружать машины, чтобы вновь получить к ним доступ.

Основанная на очередях модель программирования Erlang позволяет с большим удовольствием писать код, но с другой стороны — это ахиллесова пята в продакшне. Каждая очередь в Erlang является неограниченной. Виртуальная машина не будет бросать исключения или ограничения количества сообщений в очереди. Иногда процесс останавливает обработку сообщений в связи с ошибкой, или процесс просто не может успеть за потоком сообщений направляемых к нему. В этом случае, Erlang просто позволяет очереди сообщений для этого процесса расти, пока VM не будет убита или пока не блокируется машина, что случается раньше.

Это означает, что при запуске «больших» Erlang VM в продакшн-среде вам нужна проверка на уровне операционной системы, которая будет убивать процесс, если используется слишком много памяти.

Таким образом, я считаю, что модель памяти Erlang с частными кучами может быть очень мощным инструментом. Она избавляет от целых классов механизмов блокировок во время выполнения и, что означает, что она будет масштабироваться лучше, чем Java. С другой стороны, жесткие ограничения Java на память дают выигрыш, когда ваша система будет зафлужена или будет под DDoS'ом.

Ну, и на последок:

Существуют параметры командной строки для Erlang VM, позволяющие перейти от использования топологии частной кучи к использованию топологии общей кучи.

Мне нравятся Erlang и Java. Их трудно сравнивать, потому что слишком мало общего для разработчика. В общем, всё же для большинства систем я хотел бы использовать Java. У неё лучшая поддержка различных инструментов и число доступных библиотек просто ошеломляет. Я выбираю Erlang в случае, когда нужна поток-ориентированная системы обмена сообщениями. Вот где Erlang-модель программирования действительно оказывается великолепной.

Ссылки:
Erlang memory architecture vs Java memory architecture from our JCG partner Kees Jan Koster at Java-Monitor


Счастливого кодирования! Не забывайте делиться!
Byron

=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
По ссылке на оригинал есть интересные (и опровергающие) комментарии, заинтересованным читать обязательно!
Поделиться публикацией

Комментарии 40

    +1
    «за каждый день спектакля я считаю, что частная модель памяти кучи быть очень мощным инструментом в Erlang ящик «с. Она режет целые классы механизмы блокировки из системы во время выполнения и, что означает, что она будет масштабироваться лучше, чем Java будет с той же целью. Java-жесткие ограничения на память сохранить бекон, когда ваша система затопления или DDoSed.»

    Made my day!
      0
      Извиняюст, случайно вставился лишний фрагмент ) Убрал )
        0
        * Извиняюсь
        Да чтож такое )
          0
          По-моему совсем не лишний. Отлично вписался.
            +1
            красота!
            немедля вернуть!

            и меня немного ввело в ступор

            >Мне кажется, что для Erlang-потока требуется около 512 байт. Для Java-потоков, как правило, необходимо около 512 килобайт, что примерно в 1000 раз больше.

            может всетаки точно в 1024?
              0
              >Мне кажется, что для Erlang-потока требуется около 512 байт. Для Java-потоков, как правило, необходимо около 512 килобайт, что примерно в 1000 раз больше.

              может всетаки точно в 1024?

              Ну, в оригинале именно так… Тем более и там и там используется ОКОЛО 512… Видимо поэтому, ПРИМЕРНО в 1000 раз )
                0
                софистика
                +3
                Нет. кило- — это ровно 10³.
                  +1
                  вы на кибибайт намекаете?
                  не, я пока по старинке :)

                  да и в контексте статьи, с моей стороны, было неразумно прицепиться к этому мнимому несоответсвию.

                  думаю стоит лучше выяснить как килять зажравшиеся процессы и главное какие типы задач наиболее подвержены такому разрастанию в памяти.
                    +1
                    >выяснить как килять зажравшиеся процессы

                    Вы их не перекармливайте ;)
                      0
                      Их кормят злые анонимусы из ионной пушки ;-)
                      0
                      Есть ровно два типа утечек памяти, требующих прибивания процесса:

                      1) невыгребание сообщений
                      2) накопление данных в состоянии процесса без их сброса

                      Других ошибок нет и быть не может by design. Долго и неоднократно обсуждали это в рассылке по эрлангу, но ни к чему внятному не пришли. Моё мнение — трекать процесс с максимально забитой памятью и в случае OOM, первым прибивать его. Дешево, практично и логично.
                    +1
                    512 кибибайт в 1024 раз больше 512 байт
                    512 килобайт в 1000 раз больше 512 байт

                    всегда ваша, матчасть
              • НЛО прилетело и опубликовало эту надпись здесь
                  +2
                  Опции чтобы менять дефолтные значения, которые, как правило являются дефолтными.
                    0
                    TLAB — это чуть другое, это выделение памяти под объект без использования блокировок. Но это для объектов молодого поколения разумного размера.
                    0
                    можно приложить ссылочку и на саму дисертацию) www.it.uu.se/research/publications/lic/2005-001/
                    • НЛО прилетело и опубликовало эту надпись здесь
                        +2
                        краткое содержание:

                        эрланг поток 512 байт java поток 1000 раз больше эрланг функциональный java общая куча эрланг куча каждому потоку много планировщиков очередь растёт память кончается машины подвисают
                          +1
                          >Я выбираю Erlang в случае, когда нужна поток-ориентированная системы обмена сообщениями.
                          Как насчет Scala? Вроде бы она как раз совмещает в себе преимущества Java и, отчасти, Erlang, особенно если использовать вместе с Akka… Конечно это касается языка, виртуальная машина все равно jvm.
                            +1
                            А еще у нее более приятный синтаксис, что тоже немаловажно.
                              +1
                              Язык богаче и выразительнее, синтаксис потом будет.
                                +1
                                Вы про Эрланг? Когда будет? Дело в том, что ему уже больше двадцати лет и все никак.
                                  +2
                                  Вон Elixir попробуйте если синтаксис уж совсем не нравится (хотя как по мне, то ничего так синтаксис, сносный)
                                  +1
                                  Может быть, со мной что-то не так, но почти во всём (кроме, разве что, доступа ко вложенным структурам данных — без синтаксического сахарка тяжеловато) мне эрланг больше питона нравится.
                                    +1
                                    Я читал наискосок, подумал что вы про скалу и джаву. :-)

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

                                    Конечно есть фанатики, орущие про ';', '.', ',', но это их удел. Синтаксис специфичен, но не более.
                                +1
                                У Акки не все хорошо с документацией и стабильностью, и почти нет эксклюзивных для jvm фишек. Ну и Эрланг это тоже не только много потоков и message-passing.
                                  0
                                  Если говорить о потоковости то Scala я так подозреваю переисспользует модель из Java.
                                  Java уже проходила этап своих потоков, потому пришлось вернуться к native потокам.
                                  У обоих моделей есть свои как плюсы так и минусы. Есть подозрение что если с этих Erlang потоков нужно обращение к ресурсам системы то большинство преимуществ будут потеряны.
                                    0
                                    У Erlang VM есть отдельный пул потоков для i/o. Там с этим всё продумано, он создавался исключительно под нужды телекома.
                                    0
                                    Мне кажется, что статья предвзята. Автор анализирует, что плохого в нативном трэд мэнеджменте JVM при этом абсолютно игнорирую Akka, нацеленный как раз на реализацию микротрэдов из Erlang в JVM.
                                      0
                                      1) это джава
                                      2) когда её отладят и вылижут из неё хотя бы основную массу детских глюков, будет с чем сравнивать
                                      Мой товарищ недавно нашел утечку памяти в unlink (!) скалы.
                                      3) она _никогда_ не будет такой же стабильной в части использования памяти, потому что куча всё равно общая
                                      +1
                                      К вопросу об ожидаемой критике. Просто интересно. Почему вы считаете, что на функциональных языках нельзя писать реальные приложения?
                                        0
                                        Вопрос не ко мне, а к автору — я лишь перевел ) лично я функциональные языки обожаю. но к слову сказать, ведь «реальных» приложений на них действительно очень мало.
                                          0
                                          Мало. Хотя это вопрос терминологии, что считать «реальным» приложением. Функциональные языки не особо востребованы в бизнес-сфере, что, по-моему, им только в плюс
                                            0
                                            Это не мешает пользоваться функциональной парадигмой в «реальных» приложениях ;)

                                            Буквально недавно начал нырять в функциональный Ruby, открыл для себя очень аккуратные ленивые списки :)

                                            Вообще много где можно писать в функциональном стиле, надо просто знать как это хорошо делать в контексте используемого языка. Иногда получаются очень красивые решения.
                                          0
                                          Семантика копирования, а не копирование семантики. ;)
                                            0
                                            Никто не упоминул о таком свойстве JVM, как невозможность возвратить ядру операционной системы страниц памяти, если они больше не нужны — JVM в течении жизни процесса умеет только расти. Erlang это умеет возвращать.

                                            Это очень актуально в облаках, когда оперативная память выделяется по необходимости.

                                            Только полноправные пользователи могут оставлять комментарии. Войдите, пожалуйста.

                                            Самое читаемое