Always ensure resources are properly released, especially in exception paths. Use try-finally blocks to guarantee cleanup of buffers, streams, and other resources even when errors occur.
Always ensure resources are properly released, especially in exception paths. Use try-finally blocks to guarantee cleanup of buffers, streams, and other resources even when errors occur.
Common mistakes include:
Example of problematic code:
public void write(ChannelHandlerContext ctx, Object msg, ChannelPromise promise) throws Exception {
ByteBuf content = ctx.alloc().buffer();
dohQueryEncoder.encode(ctx, (DnsQuery) msg, content);
HttpRequest request = createRequest(content);
// If an exception occurs here, both content and msg will leak
super.write(ctx, request, promise);
}
Better implementation:
public void write(ChannelHandlerContext ctx, Object msg, ChannelPromise promise) throws Exception {
DnsQuery query = (DnsQuery) msg;
ByteBuf content = ctx.alloc().buffer();
try {
dohQueryEncoder.encode(ctx, query, content);
HttpRequest request = createRequest(content);
ctx.write(request, promise);
} finally {
content.release();
query.release();
}
}
Also ensure proper cleanup in lifecycle methods like handlerRemoved()
and doClose()
to prevent leaks, and when throwing exceptions, release any allocated resources first:
if (!IoUring.isRegisterBufferRingSupported()) {
// Close ringBuffer before throwing to ensure we release all memory on failure
ringBuffer.close();
throw new UnsupportedOperationException("io_uring_register_buffer_ring is not supported");
}
When handling error conditions, prefer specific exceptions with clear messages:
// Bad
if (encoderFactory == null) {
throw new Error();
}
// Good
if (encoderFactory == null) {
throw new IllegalStateException("Couldn't find CompressionEncoderFactory: " + targetContentEncoding);
}
Enter the URL of a public GitHub repository