Почему нам нужно вручную обрабатывать подсчет ссылок для 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 для размещения/освобождения объекта.
Ответы
Ответ 1
Прямые буферы опосредованно освобождаются сборщиком мусора. Я дам вам прочитать ответ на этот вопрос, чтобы понять, как это происходит: Собираются ли мусорщики оболочки DirectByteBuffer Java?
Буферы кучи необходимо скопировать в прямую память, прежде чем обрабатывать ядро, когда вы выполняете операции ввода-вывода. Когда вы используете прямые буферы, вы сохраняете операцию копирования и основное преимущество использования прямых буферов. Недостатком является то, что распределение прямой памяти значительно дороже, чем выделение из кучи java, поэтому Netty представила концепцию объединения.
Объединение объектов в Java - это полемическая тема, но выбор Netty для этого, похоже, окупился, а статья Twitter, которую вы указали, показывает некоторые доказательства этого. Для конкретного случая выделения буферов, когда размер буфера велик, вы можете видеть, что он действительно приносит пользу как в случаях прямого, так и в кучном буфере.
Теперь для объединения в буфер GC не восстанавливает буфер при объединении, потому что либо ваше приложение имеет одну или несколько ссылок на него, в то время как вы используете буфер; или Netty имеет ссылку на него, когда он только что был выделен и еще не был предоставлен вашему приложению или после того, как ваше приложение использовало его и вернуло его в пул.
Утечки будут происходить, когда ваше приложение после использования буфера и не будет продолжать ссылаться на него, не вызывает release()
, что на самом деле означает вернуть его обратно в пул, если у вас больше нет ссылку на него. В таком случае буфер будет в конечном итоге собираться мусором, но Netty-пул не узнает об этом. Затем пул станет верить, что вы используете все больше и больше буферов, которые никогда не возвращаются в пул. Вероятно, это приведет к утечке памяти, потому что, даже если сами буферы собирают мусор, внутренние структуры данных, используемые для хранения пула, не будут.
Ответ 2
ByteBuf использует память кучи, поэтому ее не видно GC. Вот почему вам нужно обновить счетчик ссылок (иначе нетто не узнает, когда выпустить этот элемент).
С наилучшими пожеланиями