Подтвердить что ты не робот

Почему нам нужно вручную обрабатывать подсчет ссылок для Netty ByteBuf, если JVM GC все еще на месте?

Согласно книге Netty in Action v10, reference counting используется для обработки пула ByteBuf. Но JVM не знает о подсчете ссылок netty, поэтому JVM все еще может GC ByteBuf. Если да, почему нам все еще нужно заботиться о подсчете ссылок и вручную вызывать метод release()?

Я цитировал некоторых из книги < Netty in Action v10 > добавить некоторый контекст.

Одним из компромиссов подсчета ссылок является то, что пользователь должен быть тщательно, когда потребляют сообщения. Пока JVM все еще сможет GC такое сообщение (поскольку оно не известно о подсчете ссылок) это сообщение не будет возвращено в пул, из которого он может быть получен до. Таким образом, есть хорошие шансы, что у вас не хватит ресурсов на один пункт, если вы не тщательно отпустите эти сообщения.

И некоторые связанные потоки: Владение буфером в Netty 4: Как управляется жизненный цикл буфера?

https://blog.twitter.com/2013/netty-4-at-twitter-reduced-gc-overhead

ADD 1

(Ниже я еще кое-что понимаю).

A ByteBuf можно классифицировать из 2-х перспектив:

1. Pooled or Unpooled
2. Heap-based or Direct

Таким образом, может быть 4 комбинации:

(a) Pooled Heap-based
(b) Pooled Direct
(c) Unpooled Heap-based
(d) Unpooled Direct

Только (a) и (c) подвержены влиянию механизма JVM GC, поскольку они основаны на куче.

В приведенной выше цитате из < Netty in Action v10 > , я думаю, что сообщение означает объект Java, который находится в категории (a).

Одно конечное правило: если объект Java GCed, он полностью исчез. Итак, ниже я думаю, что Netty делает:

  • Для (a) распределитель Netty ДОЛЖЕН использовать JVM GC, полагая, что объект никогда не должен быть GCed. А затем используйте ref counting для перемещения объекта из/обратно в пул. Это еще одна форма жизненного цикла.

  • Для (b), JVM GC не участвует, поскольку это не JVM Heap-based. И Netty allocator необходимо использовать ref counting для перемещения объекта из/обратно в пул.

  • Для (c) JVM GC несет полную ответственность за контроль жизни объекта. Netty-распределитель просто предоставляет API для размещения объекта.

  • Для (d) JVM GC не участвует. И никакого объединения не требуется. Таким образом, Netty allocator должен предоставить API для размещения/освобождения объекта.

4b9b3361

Ответ 1

Прямые буферы опосредованно освобождаются сборщиком мусора. Я дам вам прочитать ответ на этот вопрос, чтобы понять, как это происходит: Собираются ли мусорщики оболочки DirectByteBuffer Java?

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

Объединение объектов в Java - это полемическая тема, но выбор Netty для этого, похоже, окупился, а статья Twitter, которую вы указали, показывает некоторые доказательства этого. Для конкретного случая выделения буферов, когда размер буфера велик, вы можете видеть, что он действительно приносит пользу как в случаях прямого, так и в кучном буфере.

Теперь для объединения в буфер GC не восстанавливает буфер при объединении, потому что либо ваше приложение имеет одну или несколько ссылок на него, в то время как вы используете буфер; или Netty имеет ссылку на него, когда он только что был выделен и еще не был предоставлен вашему приложению или после того, как ваше приложение использовало его и вернуло его в пул.

Утечки будут происходить, когда ваше приложение после использования буфера и не будет продолжать ссылаться на него, не вызывает release(), что на самом деле означает вернуть его обратно в пул, если у вас больше нет ссылку на него. В таком случае буфер будет в конечном итоге собираться мусором, но Netty-пул не узнает об этом. Затем пул станет верить, что вы используете все больше и больше буферов, которые никогда не возвращаются в пул. Вероятно, это приведет к утечке памяти, потому что, даже если сами буферы собирают мусор, внутренние структуры данных, используемые для хранения пула, не будут.

Ответ 2

ByteBuf использует память кучи, поэтому ее не видно GC. Вот почему вам нужно обновить счетчик ссылок (иначе нетто не узнает, когда выпустить этот элемент). С наилучшими пожеланиями