【问题标题】:Netty 4/5 deterministic buffer leak detection that can be used in unit tests可用于单元测试的 Netty 4/5 确定性缓冲区泄漏检测
【发布时间】:2016-05-19 00:27:58
【问题描述】:

我阅读了很多关于 Netty4 中缓冲区泄漏检测的内容,在我看来,似乎没有确定性的方法可以在单元测试中检测此类泄漏。

然而,这种特性对于单元测试的重要性是如此之大,以至于没有明确的指导方针来说明如何去做,感觉非常错误。

此外,大多数来源包括原始文档 http://netty.io/wiki/reference-counted-objects.html 通过给出如下模糊的提示让事情变得非常混乱:

“以下输出显示了我们的单元测试 (XmlFrameDecoderTest.testDecodeWithXml()) 的泄漏:”

听起来有一种方法可以在单元测试中确定性地检测缓冲区分配器中的泄漏,但实际上不存在这样的事情,正如 Trustin Lee 本人在他的回答中指出的那样(下面的链接)。

难怪这被各种不知道的来源转发了几十次,只是复制粘贴单词而没有测试。

*) Trustin Lee 建议在以下主题中的某些繁忙工作负载下运行应用程序 30 秒。 Netty 4/5 does not actually detect resource leak of bytebuf? 但是,这不会触发 ResourceLeakDetector 的检测或任何输出。

*) 我还尝试了以下主题中建议的 GC 技巧 How to force garbage collection in Java? 但这也没有任何区别。

GC 是如此不可预测,以至于很难想象如何利用 ResourceLeakDetector 来创建干净彻底的缓冲区泄漏单元测试。

*) 另一种方法是测试运行测试时创建的每个 ByteBuf 的 refCnt。 但有时不可能获取每个这样的引用,因为接口可能将 String 声明为输入参数,然后其实现会在内部创建和释放 ByteBuf 实例,并且该引用将无法用于单元测试,但是如果发布没有'不会发生它会产生泄漏,在单元测试中没有机会检测到。

*) 我也找不到一种简单的方法来从分配器中获取所有现有缓冲区的列表,否则可以只检查每个缓冲区的 refCnt。


我想知道是否有人可以分享以确定性方式工作并且可以在单元测试中实际使用的最佳实践,以在使用 Netty 缓冲区分配器的大型代码库中持续发现缓冲区泄漏。

到目前为止,对我来说,单元测试似乎对此毫无用处,除非您在单元测试中长时间运行完整的服务器(顺便说一下,这也不能保证任何事情,只是理论上增加你的机会)。 据我所知,没有充分的理由存在这样的测试限制,但我们拥有我们所拥有的。

互联网上关于这个主题的信息太多令人困惑,遗憾的是,这些信息来自 Netty 文档本身,我真的希望以直截了当的方式陈述事实。

即使我的问题的答案是“不可能”,但仅提供此文本可能会为一些人节省大量研究时间。


附:一个非常简单的例子来演示缺少输出。 如果有人能说出让这段代码产生泄漏输出需要进行哪些更改,我将不胜感激。

http://gist.github.com/codekrolik/e55b8ece07270f40aad85f691696fe6a

【问题讨论】:

  • 另一个想法是计算分配和释放的数量,并确保没有悬空的活动缓冲区。出于这个原因,我试图利用可从分配器访问的有关竞技场的信息。然而,返回的数字的不一致是如此令人难以置信,以至于它们肯定不能用于产生稳定的泄漏感知单元测试。 gist.github.com/codekrolik/6aa035ac650ea2972e532227a355a0e4
  • 例如,当我运行 50000 个分配和释放时,arenas 返回的统计信息如下所示: directActive 0 directAlloc 1 directDealloc 1 heapActive 0 heapAlloc 0 heapDealloc 0 但是如果我注释掉 release 行,突然输出被转换 directActive 50000 directAlloc 50000 directDealloc 0 heapActive 0 heapAlloc 0 heapDealloc 0

标签: java unit-testing memory-leaks garbage-collection netty


【解决方案1】:

所以我设法让单元测试为我工作。

机制如下:

1) 创建一个禁用缓存的 PooledBufferAllocator,正如 https://github.com/netty/netty/issues/5275 中所建议的那样

PooledByteBufAllocator alloc = new PooledByteBufAllocator(true, 1, 1, 8192, 11, 0, 0, 0);

2) 确保所有 Bootstrap 都使用这个分配器

一个。客户

Bootstrap clientBootstrap = new Bootstrap();
clientBootstrap.option(ChannelOption.ALLOCATOR, alloc);

b.服务器

ServerBootstrap serverBootstrap = new ServerBootstrap();
serverBootstrap.option(ChannelOption.ALLOCATOR, alloc)
    .childOption(ChannelOption.ALLOCATOR, alloc);

3) 测试完成后,检查直接缓冲区和堆缓冲区的缓冲区泄漏

assertEquals(0, getActiveDirectBuffers(alloc));
assertEquals(0, getActiveHeapBuffers(alloc));

int getActiveDirectBuffers(PooledByteBufAllocator alloc) {
    int directActive = 0, directAlloc = 0, directDealloc = 0;
    for (PoolArenaMetric arena : alloc.directArenas()) {
        directActive += arena.numActiveAllocations();
        directAlloc += arena.numAllocations();
        directDealloc += arena.numDeallocations();
    }
    System.out.println("directActive " + directActive + " directAlloc " + directAlloc + " directDealloc " + directDealloc);
    return directActive;
}

int getActiveHeapBuffers(PooledByteBufAllocator alloc) {
    int heapActive = 0, heapAlloc = 0, heapDealloc = 0;
    for (PoolArenaMetric arena : alloc.heapArenas()) {
        heapActive += arena.numActiveAllocations();
        heapAlloc += arena.numAllocations();
        heapDealloc += arena.numDeallocations();
    }
    System.out.println("heapActive " + heapActive + " heapAlloc " + heapAlloc + " heapDealloc " + heapDealloc);
    return heapActive;
}

【讨论】:

    【解决方案2】:

    对于单元测试,System.gc() 对我有用。 (我不确定它有多可靠,但它似乎足够可靠,足以在测试中引起 gc 以捕获泄漏)。但是,对我来说,单元测试中的泄漏主要是因为我忘记在测试中释放缓冲区(不是因为服务器代码本身有泄漏)。

    正如您提到的,集成和/或负载测试可能有助于发现服务器中的任何泄漏。

    【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2011-09-28
    • 2010-09-15
    • 1970-01-01
    • 2016-01-05
    • 1970-01-01
    • 1970-01-01
    • 2018-02-23
    • 1970-01-01
    相关资源
    最近更新 更多