Почему мы должны вручную обрабатывать подсчет ссылок для Netty ByteBuf, если JVM GC все еще на месте?
Согласно Книге Netty in Action v10, reference counting используется для обработки объединения ByteBuf. Но JVM не знает о подсчете ссылок netty, поэтому JVM все еще может GC ByteBuf. Если да, то почему мы все еще должны заботиться о подсчете ссылок и вручную вызывать метод release()?
Я процитировал кое-что из книги "Нетти в действии v10", чтобы добавить некоторый контекст.
Одним из компромиссов подсчета ссылок является то, что пользователь должен быть
осторожно, когда потребляете сообщения . А JVM будет по-прежнему сможете
GC такое сообщение (так как оно не знает о подсчете ссылок) это
сообщение не будет помещено обратно в пул, из которого оно может быть получено
до. Таким образом, велики шансы, что у вас кончатся ресурсы в
один момент, если вы не будете тщательно выпускать эти сообщения.
И некоторые связанные темы:
владение буфером в Netty 4: Как происходит жизненный цикл буфера удалось?
Https://blog.twitter.com/2013/netty-4-at-twitter-reduced-gc-overhead
Добавить 1
(ниже приводится еще кое-что из моего понимания.)
A ByteBuf можно классифицировать с двух точек зрения:
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) подвержены влиянию механизма GC JVM, поскольку они основаны на куче.
В приведенной выше цитате из , я думаю, что сообщение означает Java объект, находящийся в категории (А).
Одно из главных правил заключается в том, что если объект Java GCed, он полностью исчез. Итак, ниже я думаю, что делает Нетти:
Для (a), NETTY allocator должен обмануть JVM GC, чтобы поверить, что объект никогда не должен быть GCed. А затем используйте ref подсчет, чтобы переместить объект из / обратно в бассейн. это еще одна форма жизненного цикла .
Для (b), JVM GC не участвует, поскольку он не основан на куче JVM. И распределитель Нетти нужно использовать ref подсчет, чтобы переместить объект из / обратно в бассейн.
Для (c), СПМ ГК берет на себя полную ответственность по контролю за жизнью объекта. Netty allocator просто предоставляет API для выделения объекта.
В случае (d) СПМ GC не участвует. И никакого объединения не требуется. Поэтому Netty allocator нужно только предоставить API для выделения / освобождения объекта.
2 ответов:
Прямые буферы косвенно освобождаются сборщиком мусора. Я позволю вам прочитать ответ на этот вопрос, чтобы понять, как это происходит: являются ли Java DirectByteBuffer wrappers собранным мусором?
Буферы кучи должны быть скопированы в непосредственную память перед обработкой ядром, когда вы выполняете операции ввода-вывода. Когда вы используете прямые буферы, вы сохраняете эту операцию копирования, и это главное преимущество использования прямых буферов. Недостаток в том, что прямой выделение памяти разумно дороже, чем выделение из кучи java,поэтому Нетти ввела концепцию пула.
Объединение объектов в Java-этополемическая Тема , но выбор Netty для этого, кажется, окупился, и статьяTwitter , которую вы процитировали, показывает некоторые доказательства этого. В частном случае выделения буферов, когда размер буфера велик, вы можете видеть, что это действительно приносит пользу как в прямом, так и в кучном буфере случаи.
Теперь для пула, GC не восстанавливает буфер, когда они объединены в пул, потому что либо ваше приложение имеет одну или несколько ссылок на него, пока вы используете буфер; или пул Netty имеет ссылку на него, когда он только что был выделен и еще не был передан вашему приложению или после того, как ваше приложение использовало его и вернуло его обратно в пул.
Утечки будут происходить, когда ваше приложение, использовав буфер и не сохраняя никаких дальнейших ссылок на него, не вызывает
release(), что на самом деле означает положить его обратно в пул, Если у вас нет никаких дальнейших ссылок на него. В таком случае буфер в конечном счете будет собран мусором, но пул Нетти не будет знать об этом. Затем пул будет расти, полагая, что вы используете все больше и больше буферов, которые никогда не возвращаются в пул. Это, вероятно, приведет к утечке памяти, потому что, даже если сами буферы являются собранным мусором, внутренние структуры данных, используемые для хранения пула не будет.
ByteBuf является использование динамической памяти , поэтому его не видно на ГК. Вот почему вам нужно обновить количество ссылок ( в противном случае Нетти не будет знать, когда выпустить элемент ). С наилучшими пожеланиями
Comments