【问题标题】:Buffer ownership in Netty 4: How is buffer life-cycle managed?Netty 4 中的缓冲区所有权:如何管理缓冲区生命周期?
【发布时间】:2015-02-23 22:35:00
【问题描述】:

我一直在尝试编写一个 HTTP 客户端来同时获取多个提要(最多 1k),这也是学习 Netty 4 的练习。

我的问题是,是否有很好的解释新的 ByteBuf 基础设施是如何工作的?谁“拥有”它们,它们是如何共享的(它们是吗?)? ChannelPipeline 中的每个 ChannelHandler 是否都有自己的 ByteBuf?

这是一个让我感到困惑的例子:

我将以下类的实例添加到 HTTP 客户端管道:

public class MyFilter extends MessageToMessageDecoder<HttpObject> {

    @Override
    protected Object decode(ChannelHandlerContext ctx, HttpObject msg) throws Exception {
        // do some work, but leave msg unchanged
        BufUtil.retain(msg); // Why do I need to call BufUtil.retain(msg) ???
        return msg;
}

如果我不在 msg 上调用 BufUtil.retain,它似乎会得到 GCd,并且我会得到各种虚假错误。

【问题讨论】:

    标签: netty


    【解决方案1】:

    HttpContent 扩展 ReferenceCounted 以跟踪它所持有的缓冲区的生命周期。当 ReferenceCounted 被实例化时,它的生命周期以 refCnt1 开始。如果您在其上调用retain(),则增加refCntrefCntrelease() 上减少,并且一旦refCnt 变为0,底层资源(在这种情况下为ByteBuf)就会被销毁。

    通常,处理程序不需要保留对其完成处理的消息的引用,因为消息通常在处理后被丢弃或转换为其他内容。因此,一旦您的处理程序处理完毕,就必须在消息上调用 release() 方法。这通常容易出错,并且很容易导致资源泄漏。

    为避免难以追踪的泄漏,请扩展 SimpleChannelInboundHandler,它会在处理完消息后自动调用 release()

    有关 Netty 中引用计数的更多信息,请阅读this wiki page。它还为您提供了有关如何利用 Netty 的缓冲区泄漏检测机制排除缓冲区泄漏的详细信息。

    【讨论】:

    • 嗨,谢谢。在性能至关重要的环境中,这是有道理的。要是能更明显就好了……
    • @trustin - 我也对所有这些引用计数渗入用户 API 感到困惑和惊讶。 API 设计应该“做最少令人惊讶的事情”和“尽可能简单”。也许您可以使用熟悉的 Java 构造来代替:资源,如 try-with-resources。或者只是让消息 Object 默认表现得像用户期望的那样,并且只能通过单独的接口获得高性能优化但更复杂的版本;性能不如快速构建应用程序并确信它不会泄漏内存那么重要。
    • @Ryan,如果在 Java 中有明确的方法来指定对象的生命周期,例如 C++ 中的析构函数,那么在大多数情况下,我们将永远不需要引入引用计数。但是,Java 没有这样的东西,因此引用计数是管理缓冲区的最有效方法。这并不漂亮,但不幸的是,这是安全处理直接缓冲区的唯一方法。顺便说一句,Netty 中的缓冲区泄漏比较容易找到:netty.io/wiki/reference-counted-objects.html#wiki-h2-10
    • @smwikipedia 'or' 应该是 'and因此' 确实。感谢您的建议。
    • @smwikipedia 对于您提到的主题,我想选择的答案已经很棒了。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2013-01-16
    • 2012-03-27
    • 1970-01-01
    • 2012-12-05
    • 2022-01-03
    • 2017-07-12
    • 1970-01-01
    相关资源
    最近更新 更多