Темный мир Джруби - Дж. Руби с рельсами под микроскопом

Это руководство по пониманию и использованию Jruby с Ruby on Rails.

Разобраться в ошибках jruby станет намного проще, если вы поймете, как работают опции, сборщики мусора и JVM. В последнее время я потратил много времени на работу с jruby и решил написать сообщение, в котором резюмирует любую информацию, которую я, возможно, нашел в Интернете, чтобы лучше понять, с чем я имел дело. Большая часть информации ниже представляет собой комбинацию сообщений в блогах и статей, которые помогли мне лучше понять, как Jruby работает под капотом.

Что вы найдете в этом сообщении:

  • Что такое Руби?
  • Почему я должен использовать JRuby?
  • Как установить JRuby?
  • Что такое JRuby -S
  • Куда поставить параметры JVM?
  • В чем разница между JAVA_OPTS и JRUBY_OPTS?
  • Памятка по опциям JVM
  • Понимание java.lang.OutOfMemoryError: превышен предел накладных расходов GC - как работает сборка мусора?
  • Решение для OutOfMemoryError в Java и Jruby
  • Как решить java.lang.OutOfMemoryError: пространство кучи Java
  • Как решить java.lang.OutOfMemoryError: PermGen space
  • Основные моменты, которые вы должны знать о сборке мусора в Java
  • Инструменты

Что такое JRuby?

JRuby - это просто Java-реализация языка программирования Ruby.

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

Почему я должен использовать JRuby?

  1. Используйте библиотеки Java и Ruby (драгоценные камни)
  2. Используйте существующую платформу Java для развертывания приложений Ruby или Ruby on Rails.
  3. Возможность вызывать или расширять классы Java из Ruby (включая Java-бины, управляемые Spring)
  4. Воспользуйтесь менее подробным и более приятным опытом написания кода на Ruby.
  5. Используйте многопоточность и параллелизм

Как установить JRuby?

Прочтите jruby Руководство по началу работы.

В OSX при использовании RVM я делаю:

$ rvm install jruby

Что такое Jruby -S?

Рекомендуемый способ запуска rake, gem, rails и других командных команд (известных как исполняемые команды системного уровня) в JRuby - всегда использовать jruby -S

$ jruby -S rake db:migrate

Параметр -S указывает JRuby использовать свою версию установленного двоичного файла, в отличие от какой-либо другой версии (например, версии MRI), которая может быть в вашем PATH.

Куда поставить параметры JVM?

Вы можете поместить их в JRUBY_OPTS из командной строки.

JRUBY_OPTS='— 2.0'

другой пример:

JRUBY_OPTS='-J-Xmx2G'

вы также можете загрузить их при запуске вашего сервера

$ jruby -J-Xmx2G -J-XX:+HeapDumpOnOutOfMemoryError -S rails s puma

Если вы используете RVM, вы можете поместить export JRUBY_OPTS = "…" в .rvmrc вашего проекта в нижней части файла.

В чем разница между JAVA_OPTS и JRUBY_OPTS

JAVA_OPTS используется программой запуска `jruby` для передачи параметров JVM при ее запуске. Эта переменная среды ничего не делает, если вы напрямую используете jruby jar.

JRUBY_OPTS используется как программой запуска `jruby`, так и самим JRuby. При использовании средства запуска все аргументы командной строки будут работать так, как если бы они были переданы команде `jruby`. При прямом использовании jar будут учитываться только параметры, обработанные после запуска JVM (версия совместимости с Ruby и т. Д.). В этом последнем случае параметры, обрабатываемые только программой запуска, не будут работать (-Xjit.threshold = # style options, - manage, другие, которые вы видите, обрабатываются bin / jruby.bash).

Параметры -J обрабатываются программой запуска JRuby и используются для передачи параметров непосредственно в JVM. При использовании jar напрямую удалите -J и передайте эти параметры команде `java`.

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

Памятка по опциям JVM

Команда java -help перечисляет стандартные параметры.

Как указать параметр JVM

В зависимости от того, как мы указываем параметр JVM, его можно разделить на две части: параметры JVM, которые начинаются с -X, и те, которые начинаются с -XX:

1) Параметры JVM, начинающиеся с -X, нестандартны (не гарантируется, что они поддерживаются во всех реализациях JVM) и могут быть изменены без уведомления в последующих выпусках JDK.

2) Параметры или параметры JVM, указанные с помощью -XX, нестабильны и не рекомендуются для случайного использования. Эти параметры также могут быть изменены без предварительного уведомления.

Дополнительная информация, которую вы должны знать о параметрах JVM.

1) Логические параметры JVM могут быть включены с помощью -XX: + и могут быть отключены с помощью -XX: -.

2) Цифровые параметры JVM можно установить с помощью -XX: =. Числа могут включать «m» или «M» для мегабайт, «k» или «K» для килобайт и «g» или «G» для гигабайт (например, 32k - это sa

me as 32768).

3) Параметры String JVM могут быть установлены с помощью -XX: = и обычно используются для указания файла, пути или списка команд.

ОБЩАЯ ИНФОРМАЦИЯ

HotSpot JVM может использовать одну из 6 комбинаций алгоритмов сборки мусора, перечисленных ниже

Параметры ведения журнала GC

Параметры размера JVM

ПРОСМОТРЕТЬ ПОЛНУЮ ШПАРКУ (Шпаргалка опций HotSpot JVM GC)

Понимание java.lang.OutOfMemoryError: превышен предел накладных расходов GC - как работает сборка мусора?

Сборка мусора работает с использованием нескольких алгоритмов сборки мусора, например. Отметить и развернуть. В Java доступны разные типы сборщиков мусора для сбора различных областей памяти кучи, например. у вас есть последовательный, параллельный и параллельный сборщик мусора в Java. Новый сборщик под названием G1 (Garbage first) также представлен в JDK 1.7. Первый шаг к изучению GC - это понять, когда объект получает право на сборку мусора? Поскольку JVM обеспечивает управление памятью, разработчики Java заботятся только о создании объекта, они не заботятся об очистке, которая выполняется сборщиком мусора, но может собирать только те объекты, которые не имеют активной сильной ссылки или недоступны из какого-либо потока. Если объект, который предполагается собрать, но все еще находится в памяти из-за непреднамеренной сильной ссылки, то в Java это называется утечкой памяти. Переменные ThreadLocal в веб-приложении Java могут легко вызвать утечку памяти.

Важные моменты о сборке мусора в Java

1) Объекты создаются в куче в Java независимо от их объема, например. локальная переменная или переменная-член. при этом стоит отметить, что переменные класса или статические члены создаются в области методов пространства памяти Java, а область кучи и метода совместно используется разными потоками.

2) Сборка мусора - это механизм, предоставляемый виртуальной машиной Java для освобождения пространства кучи от объектов, которые имеют право на сборку мусора.

3) Сборка мусора освобождает Java-программиста от управления памятью, которое является важной частью программирования на C ++, и дает больше времени для сосредоточения на бизнес-логике.

4) Сборка мусора в Java выполняется потоком демона, называемым сборщиком мусора.

5) Перед удалением объекта из памяти поток сборки мусора вызывает метод finalize () этого объекта и дает возможность выполнить любую требуемую очистку.

6) Вы не можете заставить сборку мусора в Java; он сработает только в том случае, если JVM сочтет, что ему нужна сборка мусора на основе размера кучи Java.

7) В Java есть такие методы, как System.gc () и Runtime.gc (), которые используются для отправки запроса на сборку мусора в JVM, но не гарантируется, что сборка мусора произойдет.

8) Если нет места в памяти для создания нового объекта в куче, виртуальная машина Java выдает OutOfMemoryError или java.lang.OutOfMemoryError пространство кучи

9) J2SE 5 (Java 2 Standard Edition) добавляет новую функцию под названием Ergonomics. Цель эргономики - обеспечить хорошую производительность JVM с минимальной настройкой командной строки.

Я не собираюсь добавлять Когда объект получает право на сборку мусора, потому что я не думаю, что это поможет решить какую-либо проблему с jruby, но только в случае, если вы можете прочитать полное объяснение на Блог Джавина Пола

Решение для превышения предела накладных расходов ГХ

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

  • Истекшее время сборки мусора слишком велико
  • Слишком много итераций Full GC
  • Слишком много времени проведено в сборке мусора

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

Некоторые языки определяют классы во время выполнения. Каждый раз, когда вы запускаете скрипт, создается один (или несколько) новых классов, которые навсегда остаются в памяти. Если вы используете сервер, это означает, что у вас утечка памяти. Включив параметр -XX: + CMSClassUnloadingEnabled, сборщик мусора удалит классы, которые больше не используются.

Решение для OutOfMemoryError в Java и Jruby

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

Что такое java.lang.OutOfMemoryError в Java

OutOfMemoryError в Java является подклассом java.lang.VirtualMachineError, и JVM выдает ошибку java.lang.OutOfMemoryError, когда заканчивается память в куче. OutOfMemoryError в Java может появиться в любое время в куче, в основном, когда вы пытаетесь создать объект, а в куче недостаточно места для выделения этого объекта.

Разница между «java.lang.OutOfMemoryError: пространство кучи Java» и «java.lang.OutOfMemoryError: пространство PermGen»

java.lang.OutOfMemoryError: пространство кучи Java

Если вы знакомы с разными поколениями кучи и с тем, как работает сборка мусора в java, и знаете о новом, старом и постоянном поколении пространства кучи, то вы легко могли бы выяснить эту OutOfMemoryError в Java.

java.lang.OutOfMemoryError: PermGen space

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

Поскольку в большинстве JVM размер Perm Space по умолчанию составляет около «64 МБ», вы можете легко исчерпать память, если у вас слишком много классов или огромное количество строк в вашем проекте.

Важно помнить

Он не зависит от значения –Xmx, поэтому независимо от того, насколько велик ваш общий размер кучи, вы можете запускать OutOfMemory в постоянном пространстве. Хорошо, что вы можете указать размер постоянной генерации с помощью параметров JVM «-XX: PermSize» и «-XX: MaxPermSize» в зависимости от потребностей вашего проекта.

Другая причина «java.lang.OutOfMemoryError: PermGen» - это утечка памяти через загрузчики классов, которая очень часто проявляется на WebServer и сервере приложений, таких как tomcat, WebSphere, glassfish или WebLogic.

На сервере приложений разные загрузчики классов используются для загрузки различных веб-приложений, поэтому вы можете развернуть и отменить развертывание одного приложения, не затрагивая другое приложение на том же сервере, но при отмене развертывания, если контейнер каким-то образом сохраняет ссылку на любой класс, загруженный загрузчиком классов приложения, тогда этот класс и все остальные связанные классы не будут собираться сборщиком мусора и могут быстро заполнить пространство PermGen, если вы развертываете и отменяете развертывание приложения много раз.

Решение «java.lang.OutOfMemoryError: PermGen» действительно сложно, потому что сначала вам нужно знать, какой класс вызывает утечку памяти, а затем вам нужно это исправить. Другая причина OutOfMemoryError в пространстве PermGen заключается в том, что какой-либо поток, запущенный приложением, не завершает работу, когда вы отменяете развертывание приложения.

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

Другой довольно неизвестной, но интересной причиной возникновения ошибки «java.lang.OutOfMemoryError: PermGen» является введение в JVM параметров «-Xnoclassgc».

Этот параметр иногда используется, чтобы избежать загрузки и выгрузки классов, когда на него больше нет живых ссылок, просто чтобы избежать снижения производительности из-за частой загрузки и выгрузки, но использование этого параметра в среде J2EE может быть очень опасным, потому что многие фреймворки, например, Struts, Spring и т. Д. Используют отражение для создания классов, и при частом развертывании и отмене развертывания у вас может легко закончиться место в PermGen, если предыдущие ссылки не были очищены. Этот пример также указывает на то, что иногда неправильные аргументы или конфигурация JVM могут вызывать OutOfMemoryError в Java.

Таким образом, следует избегать использования «-Xnoclassgc» в среде J2EE, особенно с AppServer.

Как решить java.lang.OutOfMemoryError: пространство кучи Java

1) Простой способ решить OutOfMemoryError в java - это увеличить максимальный размер кучи с помощью параметров JVM «-Xmx512M», это немедленно устранит вашу OutOfMemoryError. Это мое предпочтительное решение, когда я получаю OutOfMemoryError в Eclipse, Maven или ANT при создании проекта, потому что в зависимости от размера проекта у вас может легко закончиться память. Вот пример увеличения максимального размера кучи JVM , Также лучше сохранить соотношение -Xmx to -Xms 1: 1 или 1: 1.5, если вы устанавливаете размер кучи в своем Java-приложении.

export JVM_ARGS="-Xms1024m -Xmx1024m"

2) Второй способ разрешения OutOfMemoryError в Java довольно сложен и возникает, когда у вас мало памяти, и даже после увеличения максимального размера кучи вы все равно получаете java.lang.OutOfMemoryError, в этом случае вы, вероятно, захотите профилировать свой приложение и ищите утечки памяти.

Вы можете использовать Eclipse Memory Analyzer для исследования дампа кучи или любой профилировщик, например Netbeans или JProbe. Это сложное решение, требующее времени на анализ и поиск утечек памяти.

Как решить java.lang.OutOfMemoryError: PermGen space

Важное примечание: Руководство по совместимости для JDK 8 говорит, что в Java 8 флаг командной строки MaxPermSize был удален. Причина в том, что постоянное поколение было удалено из кучи горячей точки и перемещено в собственную память. Постоянное поколение удалено. PermSize и MaxPermSize игнорируются, и выдается предупреждение, если они присутствуют в командной строке.

Для более старой версии JVM ‹8

Как объяснялось в предыдущем абзаце, эта ошибка OutOfMemory в java возникает, когда постоянное создание кучи заполнено. Чтобы исправить эту ошибку OutOfMemoryError в Java, вам необходимо увеличить размер кучи пермского пространства с помощью параметра JVM «-XX: MaxPermSize». Вы также можете указать начальный размер пермского пространства с помощью «-XX: PermSize» и, сохранив как начальное , так и максимальное пермское пространство, вы можете предотвратить полную сборку мусора. что может произойти при изменении размеров Perm Space. Вот как можно указать начальный и максимальный размер Perm в Java:

export JVM_ARGS="-XX:PermSize=64M -XX:MaxPermSize=256m"

Важное примечание: Начиная с Tomcat ›6.0, tomcat предоставляет функцию обнаружения утечек памяти, которая может обнаруживать многие распространенные утечки памяти в приложении Java, например утечки памяти ThreadLocal, регистрацию драйвера JDBC, цели RMI, LogFactory и поток, порожденный Интернетом. Программы. Вы можете проверить полную информацию на htp: //wiki.apache.org/tomcat/MemoryLeakProtection. Вы также можете обнаружить утечку памяти, обратившись к приложению-менеджеру, которое поставляется с tomcat. Если вы испытываете утечку памяти в каком-либо веб-приложении Java, рекомендуется запустить его на tomcat, чтобы выяснить причину OutOfMemoryError в пространстве PermGen.

Основные моменты, которые вы должны знать о сборке мусора в Java

1) Java Heap разделена на три поколения ради сборки мусора. Это молодое поколение, пожизненное или старое поколение и Пермский край.

2) Новые объекты создаются молодому поколению и впоследствии передаются старому поколению.

3) Пул строк создается в области PermGen кучи, сборка мусора может происходить в перманентном пространстве, но зависит от JVM для JVM. Кстати, из обновления JDK 1.7 пул строк перемещен в область кучи, где создаются объекты.

4) Незначительная сборка мусора используется для перемещения объекта из пространства eden в пространство выжившего 1 и выжившего 2, а основная сборка используется для перемещения объекта из молодого поколения в постоянное.

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

6) Параметры командной строки JVM –Xmx и -Xms используются для установки начального и максимального размера для Java Heap. Идеальное соотношение этого параметра - 1: 1 или 1: 1,5, исходя из моего опыта. Например, вы можете иметь либо –Xmx, и –Xms как 1 ГБ, либо –Xms 1,2 ГБ и 1,8 ГБ.

7) В Java нет ручного способа сделать сборку мусора

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

НАСТРОЙКА ГХ

Вот отрывок с веб-сайта Oracle о том, как выбрать коллектор:

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

Если приложение имеет небольшой набор данных (примерно до 100 МБ), то

  • выберите сборщик последовательного порта с помощью -XX: + UseSerialGC.

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

  • позвольте виртуальной машине выбрать сборщик, или
  • выберите сборщик последовательного порта с помощью -XX: + UseSerialGC.

Если (а) пиковая производительность приложения является первым приоритетом и (б) нет требований к времени паузы или паузы продолжительностью в одну секунду или более допустимы, то

  • позвольте виртуальной машине выбрать сборщик, или
  • выберите параллельный сборщик с помощью -XX: + UseParallelGC и (необязательно) включите параллельное сжатие с помощью -XX: + UseParallelOldGC

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

  • выберите параллельный сборщик с помощью -XX: + UseConcMarkSweepGC. Если доступны только один или два процессора, рассмотрите возможность использования инкрементного режима, описанного ниже.

Вы можете узнать больше о настройке в статье Oracle Настройка сборки мусора виртуальных машин. И прочтите полный урок о Выбор коллекционера.

Инструменты

Эти инструменты помогут вам профилировать ваше приложение и искать утечку памяти.

Visualgc

Visualgc расшифровывается как Visual Garbage Collection Monitoring Tool, и вы можете прикрепить его к вашей JVM-машине с активной точкой доступа. Основная сила visualgc заключается в том, что он отображает все ключевые данные в графическом виде, включая загрузчик классов, сборку мусора и данные о производительности компилятора JVM.

Целевая JVM идентифицируется идентификатором виртуальной машины, также называемым vmid. Вы можете узнать больше о параметрах visualgc и vmid здесь.

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

Eclipse Memory Analyzer (БЕСПЛАТНО)

Анализатор памяти Eclipse (MAT) - это инструмент от eclipse foundation для анализа дампа кучи java. Это помогает находить утечки загрузчика классов и утечки памяти и помогает минимизировать потребление памяти. MAT можно использовать для анализа дампа кучи, содержащего миллионы объектов, а также помогает выявить подозреваемые в утечке памяти. Смотрите здесь для получения дополнительной информации.

YourKit

Хорошо для анализа дампа кучи, но не бесплатно.

Jmap

Jmap - это утилита командной строки, поставляемая с JDK6 и позволяющая делать дамп памяти из кучи в файл. Его легко использовать, как показано ниже:

jmap -dump:format=b,file=heapdump 6054

Здесь файл указывает имя файла дампа памяти, который называется «дамп кучи», а 6054 - это PID вашего прогресса Java. Вы можете найти PDI с помощью «ps -ef» или диспетчера задач Windows или с помощью инструмента под названием «jps» (Инструмент состояния процесса виртуальной машины Java).

Джат

Jhat ранее назывался hat (инструмент для анализа кучи), но теперь он является частью JDK6. Вы можете использовать jhat для анализа файла дампа кучи, созданного с помощью «jmap». Jhat также является утилитой командной строки, и вы можете запустить ее из окна cmd, как показано ниже:

jhat -J-Xmx256m heapdump

Здесь он проанализирует дамп памяти, содержащийся в файле «heapdump». Когда вы запустите jhat, он прочитает этот файл дампа кучи, а затем начнет прослушивать порт HTTP, просто укажите в браузере порт, где jhat прослушивает по умолчанию 7000, а затем вы можете начать анализировать объекты, присутствующие в дампе кучи.

Jvisualvm (БЕСПЛАТНО)

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

$ jvisualvm

Jruby Books

Удивительно, но на Amazon не так много книг о Джруби, а некоторые из них на самом деле старые. Я надеюсь увидеть больше книг в будущем.

Эта Поваренная книга предлагает практические решения для использования Java-реализации языка Ruby с целевыми рецептами для развертывания веб-приложений Rails на серверах Java, интеграции кода JRuby с технологиями Java, разработки настольных приложений JRuby с помощью наборов инструментов Java и т. Д.
Купи на Amazon

Вы узнаете, как беспрепятственно вызывать объекты Java из Ruby, и разберетесь с идиомами Java, такими как интерфейсы и перегруженные функции. Запустите код Ruby из Java и сделайте программу Java доступной для сценариев на Ruby. Узнайте, как скомпилировать Ruby в файлы .class, которые можно вызывать из Java, Scala, Clojure или любого другого языка JVM.
Получить на Amazon

Источники

Эта статья была полностью собрана благодаря замечательным источникам:

Если есть дополнительная информация, которую я могу использовать в этом документе, свяжитесь со мной в Twitter @Richardsondx или оставьте комментарий здесь.

Я также писал:

_
Ричардсон - старший разработчик, дизайнер и создатель, а также генеральный директор Rich DX Studio, студии дизайна и веб-разработки, расположенной в Торонто и специализирующейся на создании продуктов.