чтение и запись сокетов и файлов использовать только родную память? - PullRequest
3 голосов
/ 17 марта 2019

Недавно я познакомился с деталями JVM и обнаружил термин Прямая память .Ответ от @ Peter Lawrey привлек мое внимание.

Все системные вызовы, такие как чтение и запись сокетов и файлов , используют только собственную память .Они не могут использовать кучу.


Мои вопросы

  1. Это правда?
  2. Где-нибудь, где я могу сопоставить это утверждение?
  3. Означает ли это любой вызов в NIO, я просто буду использовать Прямая память ?

1 Ответ

4 голосов
/ 17 марта 2019

Собственная и кучная память при передаче через сокеты (и системные вызовы)

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

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

Второй может быть очень полезен при работе с байтовыми массивами.

Взаимодействие со сборкой мусора

Эти функции JNI могут препятствовать выполнению сборки мусора . Часто бывает выгоднее сделать копию. Это особенно верно при выполнении блокирующего системного вызова (например, чтение из сокета TCP, когда точно не известно, что ядро ​​имеет буферизованные данные для возврата). В других случаях может быть возможно обрабатывать массив постепенно, небольшими порциями, чтобы избежать длинных остановок и необходимости копий.

Из-за этих проблем текущая реализация в OpenJDK 11 не предпринимает попыток передачи с нулевым копированием в и из выделенных в куче (непрямых) байтовых буферов, даже в тех случаях, когда в ядре не будет никакой блокировки и будет не влияет на сборку мусора из-за неограниченных задержек.

Противопоказания для использования прямых байтовых буферов

Использование прямого байтового буфера с NIO имеет разные проблемы: эти буферы требуют своего рода финализации. В результате сборщик мусора не может утилизировать их так же эффективно (и быстро), как другие объекты. Как правило, целесообразно использовать прямые байтовые буферы только в том случае, если они долговечны (например, выделяются вместе с каналом, с которым они используются). Для временных буферов буферы на основе массива (или обычные массивы) в большинстве случаев лучше.

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

Старые выпуски OpenJDK

Упомянутые выше функции доступа к массиву критических секций восходят к Java 1.2. Независимо от того, делают ли отдельные виртуальные машины и сборки мусора временные копии, временные копии не определены (интерфейсы были тщательно спроектированы таким образом, что для их реализации не нужно избегать копий). В Hotspot в OpenJDK 8 эти функции JNI никогда не копируют, но, как объяснено в статье Алексея Шипилёва, влияние на сборку мусора варьируется от сборщика к сборщику.

...