Class LeakPresenceDetector<T>

java.lang.Object
io.netty.util.ResourceLeakDetector<T>
io.netty.util.LeakPresenceDetector<T>
Type Parameters:
T - The resource type to detect
Direct Known Subclasses:
LeakPresenceExtension.WithTransferableScope

public class LeakPresenceDetector<T> extends ResourceLeakDetector<T>
Alternative leak detector implementation for reliable and performant detection in tests.

Background

The standard ResourceLeakDetector produces no "false positives", but this comes with tradeoffs. You either get many false negatives because only a small sample of buffers is instrumented, or you turn on paranoid detection which carries a somewhat heavy performance cost with each allocation. Additionally, paranoid detection enables detailed recording of buffer access operations with heavy performance impact. Avoiding false negatives is necessary for (unit, fuzz...) testing if bugs should lead to reliable test failures, but the performance impact can be prohibitive for some tests.

The presence detector

The leak presence detector takes a different approach. It foregoes detailed tracking of allocation and modification stack traces. In return every resource is counted, so there are no false negatives where a leak would not be detected.

The presence detector also does not wait for an unclosed resource to be garbage collected before it's reported as leaked. This ensures that leaks are detected promptly and can be directly associated with a particular test, but it can lead to false positives. Tests that use the presence detector must shut down completely before checking for resource leaks. There are also complications with static fields, described below.

Resource Scopes

A resource scope manages all resources of a set of threads over time. On allocation, a resource is assigned to a scope through the currentScope() method. When check() is called, or the scope is closed, all resources in that scope must have been released.

By default, there is only a single "global" scope, and when check() is called, all resources in the entire JVM must have been released. To enable parallel test execution, it may be necessary to use separate scopes for separate tests instead, so that one test can check for its own leaks while another test is still in progress. You can override currentScope() to implement this for your test framework.

Static Fields

While the presence detector requires that all resources be closed after a test, some resources kept in static fields cannot be released, or there would be false positives. To avoid this, resources created inside static initializers, specifically when the allocation stack trace contains a <clinit> method, are not tracked.

Because the presence detector does not normally capture or introspect allocation stack traces, additional cooperation is required. Any static initializer must be wrapped in a staticInitializer(Supplier) call, which will temporarily enable stack trace introspection. For example:

private static final ByteBuf CRLF_BUF = LeakPresenceDetector.staticInitializer(() -> unreleasableBuffer(
            directBuffer(2).writeByte(CR).writeByte(LF)).asReadOnly());

Since stack traces are not captured by default, it can be difficult to tell apart a real leak from a missed static initializer. You can temporarily turn on allocation stack trace capture using the -Dio.netty.util.LeakPresenceDetector.trackCreationStack=true system property.