Enable a user specify an arbitrary information with ReferenceCounted.touch()

- Related: #2163
- Add ResourceLeakHint to allow a user to provide a meaningful information about the leak when touching it
- DefaultChannelHandlerContext now implements ResourceLeakHint to tell where the message is going.
- Cleaner resource leak report by excluding noisy stack trace elements
This commit is contained in:
Trustin Lee 2014-01-29 11:44:59 +09:00
parent 0235244e55
commit 8837afddf8
78 changed files with 470 additions and 12 deletions

View File

@ -51,6 +51,12 @@ public abstract class AbstractDerivedByteBuf extends AbstractByteBuf {
return this; return this;
} }
@Override
public final ByteBuf touch(Object hint) {
unwrap().touch(hint);
return this;
}
@Override @Override
public final boolean release() { public final boolean release() {
return unwrap().release(); return unwrap().release();

View File

@ -95,7 +95,12 @@ public abstract class AbstractReferenceCountedByteBuf extends AbstractByteBuf {
} }
@Override @Override
public final ByteBuf touch() { public ByteBuf touch() {
return this;
}
@Override
public ByteBuf touch(Object hint) {
return this; return this;
} }

View File

@ -706,6 +706,12 @@ final class AdvancedLeakAwareByteBuf extends WrappedByteBuf {
return this; return this;
} }
@Override
public ByteBuf touch(Object hint) {
leak.record(hint);
return this;
}
@Override @Override
public boolean release() { public boolean release() {
boolean deallocated = super.release(); boolean deallocated = super.release();

View File

@ -1880,4 +1880,7 @@ public abstract class ByteBuf implements ReferenceCounted, Comparable<ByteBuf> {
@Override @Override
public abstract ByteBuf touch(); public abstract ByteBuf touch();
@Override
public abstract ByteBuf touch(Object hint);
} }

View File

@ -45,4 +45,7 @@ public interface ByteBufHolder extends ReferenceCounted {
@Override @Override
ByteBufHolder touch(); ByteBufHolder touch();
@Override
ByteBufHolder touch(Object hint);
} }

View File

@ -1570,6 +1570,16 @@ public class CompositeByteBuf extends AbstractReferenceCountedByteBuf {
return (CompositeByteBuf) super.retain(); return (CompositeByteBuf) super.retain();
} }
@Override
public CompositeByteBuf touch() {
return (CompositeByteBuf) super.touch();
}
@Override
public CompositeByteBuf touch(Object hint) {
return (CompositeByteBuf) super.touch(hint);
}
@Override @Override
public ByteBuffer[] nioBuffers() { public ByteBuffer[] nioBuffers() {
return nioBuffers(readerIndex(), readableBytes()); return nioBuffers(readerIndex(), readableBytes());

View File

@ -74,6 +74,12 @@ public class DefaultByteBufHolder implements ByteBufHolder {
return this; return this;
} }
@Override
public ByteBufHolder touch(Object hint) {
data.touch(hint);
return this;
}
@Override @Override
public boolean release() { public boolean release() {
return data.release(); return data.release();

View File

@ -836,6 +836,11 @@ public final class EmptyByteBuf extends ByteBuf {
return this; return this;
} }
@Override
public ByteBuf touch(Object hint) {
return this;
}
@Override @Override
public boolean release() { public boolean release() {
return false; return false;

View File

@ -34,6 +34,11 @@ final class SimpleLeakAwareByteBuf extends WrappedByteBuf {
return this; return this;
} }
@Override
public ByteBuf touch(Object hint) {
return this;
}
@Override @Override
public boolean release() { public boolean release() {
boolean deallocated = super.release(); boolean deallocated = super.release();

View File

@ -820,6 +820,12 @@ public final class SwappedByteBuf extends ByteBuf {
return this; return this;
} }
@Override
public ByteBuf touch(Object hint) {
buf.touch(hint);
return this;
}
@Override @Override
public boolean release() { public boolean release() {
return buf.release(); return buf.release();

View File

@ -80,6 +80,11 @@ final class UnreleasableByteBuf extends WrappedByteBuf {
return this; return this;
} }
@Override
public ByteBuf touch(Object hint) {
return this;
}
@Override @Override
public boolean release() { public boolean release() {
return false; return false;

View File

@ -805,6 +805,12 @@ class WrappedByteBuf extends ByteBuf {
return this; return this;
} }
@Override
public ByteBuf touch(Object hint) {
buf.touch(hint);
return this;
}
@Override @Override
public boolean isReadable(int size) { public boolean isReadable(int size) {
return buf.isReadable(size); return buf.isReadable(size);

View File

@ -54,6 +54,11 @@ final class ComposedLastHttpContent implements LastHttpContent {
return this; return this;
} }
@Override
public LastHttpContent touch(Object hint) {
return this;
}
@Override @Override
public LastHttpContent duplicate() { public LastHttpContent duplicate() {
return copy(); return copy();

View File

@ -78,6 +78,12 @@ public class DefaultFullHttpRequest extends DefaultHttpRequest implements FullHt
return this; return this;
} }
@Override
public FullHttpRequest touch(Object hint) {
content.touch(hint);
return this;
}
@Override @Override
public boolean release() { public boolean release() {
return content.release(); return content.release();

View File

@ -80,6 +80,12 @@ public class DefaultFullHttpResponse extends DefaultHttpResponse implements Full
return this; return this;
} }
@Override
public FullHttpResponse touch(Object hint) {
content.touch(hint);
return this;
}
@Override @Override
public boolean release() { public boolean release() {
return content.release(); return content.release();

View File

@ -73,6 +73,12 @@ public class DefaultHttpContent extends DefaultHttpObject implements HttpContent
return this; return this;
} }
@Override
public HttpContent touch(Object hint) {
content.touch(hint);
return this;
}
@Override @Override
public boolean release() { public boolean release() {
return content.release(); return content.release();

View File

@ -75,6 +75,12 @@ public class DefaultLastHttpContent extends DefaultHttpContent implements LastHt
return this; return this;
} }
@Override
public LastHttpContent touch(Object hint) {
super.touch(hint);
return this;
}
@Override @Override
public HttpHeaders trailingHeaders() { public HttpHeaders trailingHeaders() {
return trailingHeaders; return trailingHeaders;

View File

@ -32,6 +32,9 @@ public interface FullHttpMessage extends HttpMessage, LastHttpContent {
@Override @Override
FullHttpMessage touch(); FullHttpMessage touch();
@Override
FullHttpMessage touch(Object hint);
@Override @Override
FullHttpMessage duplicate(); FullHttpMessage duplicate();
} }

View File

@ -32,6 +32,9 @@ public interface FullHttpRequest extends HttpRequest, FullHttpMessage {
@Override @Override
FullHttpRequest touch(); FullHttpRequest touch();
@Override
FullHttpRequest touch(Object hint);
@Override @Override
FullHttpRequest duplicate(); FullHttpRequest duplicate();

View File

@ -32,6 +32,9 @@ public interface FullHttpResponse extends HttpResponse, FullHttpMessage {
@Override @Override
FullHttpResponse touch(); FullHttpResponse touch();
@Override
FullHttpResponse touch(Object hint);
@Override @Override
FullHttpResponse duplicate(); FullHttpResponse duplicate();

View File

@ -41,4 +41,7 @@ public interface HttpContent extends HttpObject, ByteBufHolder {
@Override @Override
HttpContent touch(); HttpContent touch();
@Override
HttpContent touch(Object hint);
} }

View File

@ -79,6 +79,11 @@ public interface LastHttpContent extends HttpContent {
return this; return this;
} }
@Override
public LastHttpContent touch(Object hint) {
return this;
}
@Override @Override
public boolean release() { public boolean release() {
return false; return false;
@ -109,6 +114,9 @@ public interface LastHttpContent extends HttpContent {
@Override @Override
LastHttpContent touch(); LastHttpContent touch();
@Override
LastHttpContent touch(Object hint);
@Override @Override
LastHttpContent duplicate(); LastHttpContent duplicate();
} }

View File

@ -401,4 +401,9 @@ public abstract class AbstractDiskHttpData extends AbstractHttpData {
public HttpData touch() { public HttpData touch() {
return this; return this;
} }
@Override
public HttpData touch(Object hint) {
return this;
}
} }

View File

@ -133,4 +133,7 @@ public abstract class AbstractHttpData extends AbstractReferenceCounted implemen
@Override @Override
public abstract HttpData touch(); public abstract HttpData touch();
@Override
public abstract HttpData touch(Object hint);
} }

View File

@ -260,8 +260,13 @@ public abstract class AbstractMemoryHttpData extends AbstractHttpData {
@Override @Override
public HttpData touch() { public HttpData touch() {
return touch(null);
}
@Override
public HttpData touch(Object hint) {
if (byteBuf != null) { if (byteBuf != null) {
byteBuf.touch(); byteBuf.touch(hint);
} }
return this; return this;
} }

View File

@ -45,4 +45,7 @@ public interface Attribute extends HttpData {
@Override @Override
Attribute touch(); Attribute touch();
@Override
Attribute touch(Object hint);
} }

View File

@ -198,4 +198,10 @@ public class DiskAttribute extends AbstractDiskHttpData implements Attribute {
super.touch(); super.touch();
return this; return this;
} }
@Override
public Attribute touch(Object hint) {
super.touch(hint);
return this;
}
} }

View File

@ -217,4 +217,10 @@ public class DiskFileUpload extends AbstractDiskHttpData implements FileUpload {
super.touch(); super.touch();
return this; return this;
} }
@Override
public FileUpload touch(Object hint) {
super.touch(hint);
return this;
}
} }

View File

@ -70,4 +70,7 @@ public interface FileUpload extends HttpData {
@Override @Override
FileUpload touch(); FileUpload touch();
@Override
FileUpload touch(Object hint);
} }

View File

@ -211,4 +211,7 @@ public interface HttpData extends InterfaceHttpData, ByteBufHolder {
@Override @Override
HttpData touch(); HttpData touch();
@Override
HttpData touch(Object hint);
} }

View File

@ -1221,6 +1221,12 @@ public class HttpPostRequestEncoder implements ChunkedInput<HttpContent> {
return this; return this;
} }
@Override
public FullHttpRequest touch(Object hint) {
content.touch(hint);
return this;
}
@Override @Override
public ByteBuf content() { public ByteBuf content() {
return content.content(); return content.content();

View File

@ -44,4 +44,7 @@ public interface InterfaceHttpData extends Comparable<InterfaceHttpData>, Refere
@Override @Override
InterfaceHttpData touch(); InterfaceHttpData touch();
@Override
InterfaceHttpData touch(Object hint);
} }

View File

@ -149,4 +149,12 @@ final class InternalAttribute extends AbstractReferenceCounted implements Interf
} }
return this; return this;
} }
@Override
public InterfaceHttpData touch(Object hint) {
for (ByteBuf buf: value) {
buf.touch(hint);
}
return this;
}
} }

View File

@ -159,4 +159,10 @@ public class MemoryAttribute extends AbstractMemoryHttpData implements Attribute
super.touch(); super.touch();
return this; return this;
} }
@Override
public Attribute touch(Object hint) {
super.touch(hint);
return this;
}
} }

View File

@ -177,4 +177,10 @@ public class MemoryFileUpload extends AbstractMemoryHttpData implements FileUplo
super.touch(); super.touch();
return this; return this;
} }
@Override
public FileUpload touch(Object hint) {
super.touch(hint);
return this;
}
} }

View File

@ -285,6 +285,12 @@ public class MixedAttribute implements Attribute {
return this; return this;
} }
@Override
public Attribute touch(Object hint) {
attribute.touch(hint);
return this;
}
@Override @Override
public boolean release() { public boolean release() {
return attribute.release(); return attribute.release();

View File

@ -316,6 +316,12 @@ public class MixedFileUpload implements FileUpload {
return this; return this;
} }
@Override
public FileUpload touch(Object hint) {
fileUpload.touch(hint);
return this;
}
@Override @Override
public boolean release() { public boolean release() {
return fileUpload.release(); return fileUpload.release();

View File

@ -81,4 +81,10 @@ public class BinaryWebSocketFrame extends WebSocketFrame {
super.touch(); super.touch();
return this; return this;
} }
@Override
public BinaryWebSocketFrame touch(Object hint) {
super.touch(hint);
return this;
}
} }

View File

@ -165,4 +165,10 @@ public class CloseWebSocketFrame extends WebSocketFrame {
super.touch(); super.touch();
return this; return this;
} }
@Override
public CloseWebSocketFrame touch(Object hint) {
super.touch(hint);
return this;
}
} }

View File

@ -146,4 +146,10 @@ public class ContinuationWebSocketFrame extends WebSocketFrame {
super.touch(); super.touch();
return this; return this;
} }
@Override
public ContinuationWebSocketFrame touch(Object hint) {
super.touch(hint);
return this;
}
} }

View File

@ -81,4 +81,10 @@ public class PingWebSocketFrame extends WebSocketFrame {
super.touch(); super.touch();
return this; return this;
} }
@Override
public PingWebSocketFrame touch(Object hint) {
super.touch(hint);
return this;
}
} }

View File

@ -81,4 +81,10 @@ public class PongWebSocketFrame extends WebSocketFrame {
super.touch(); super.touch();
return this; return this;
} }
@Override
public PongWebSocketFrame touch(Object hint) {
super.touch(hint);
return this;
}
} }

View File

@ -121,4 +121,10 @@ public class TextWebSocketFrame extends WebSocketFrame {
super.touch(); super.touch();
return this; return this;
} }
@Override
public TextWebSocketFrame touch(Object hint) {
super.touch(hint);
return this;
}
} }

View File

@ -88,4 +88,10 @@ public abstract class WebSocketFrame extends DefaultByteBufHolder {
super.touch(); super.touch();
return this; return this;
} }
@Override
public WebSocketFrame touch(Object hint) {
super.touch(hint);
return this;
}
} }

View File

@ -115,6 +115,12 @@ public class DefaultSpdyDataFrame extends DefaultSpdyStreamFrame implements Spdy
return this; return this;
} }
@Override
public SpdyDataFrame touch(Object hint) {
data.touch(hint);
return this;
}
@Override @Override
public boolean release() { public boolean release() {
return data.release(); return data.release();

View File

@ -53,4 +53,7 @@ public interface SpdyDataFrame extends ByteBufHolder, SpdyStreamFrame {
@Override @Override
SpdyDataFrame touch(); SpdyDataFrame touch();
@Override
SpdyDataFrame touch(Object hint);
} }

View File

@ -50,6 +50,12 @@ public class DefaultLastMemcacheContent extends DefaultMemcacheContent implement
return this; return this;
} }
@Override
public LastMemcacheContent touch(Object hint) {
super.touch(hint);
return this;
}
@Override @Override
public LastMemcacheContent copy() { public LastMemcacheContent copy() {
return new DefaultLastMemcacheContent(content().copy()); return new DefaultLastMemcacheContent(content().copy());

View File

@ -73,6 +73,12 @@ public class DefaultMemcacheContent extends AbstractMemcacheObject implements Me
return this; return this;
} }
@Override
public MemcacheContent touch(Object hint) {
content.touch(hint);
return this;
}
@Override @Override
public boolean release() { public boolean release() {
return content.release(); return content.release();

View File

@ -33,6 +33,9 @@ public interface FullMemcacheMessage extends MemcacheMessage, LastMemcacheConten
@Override @Override
FullMemcacheMessage touch(); FullMemcacheMessage touch();
@Override
FullMemcacheMessage touch(Object hint);
@Override @Override
FullMemcacheMessage duplicate(); FullMemcacheMessage duplicate();
} }

View File

@ -50,6 +50,11 @@ public interface LastMemcacheContent extends MemcacheContent {
return this; return this;
} }
@Override
public LastMemcacheContent touch(Object hint) {
return this;
}
@Override @Override
public LastMemcacheContent duplicate() { public LastMemcacheContent duplicate() {
return this; return this;
@ -98,6 +103,9 @@ public interface LastMemcacheContent extends MemcacheContent {
@Override @Override
LastMemcacheContent touch(); LastMemcacheContent touch();
@Override
LastMemcacheContent touch(Object hint);
@Override @Override
LastMemcacheContent duplicate(); LastMemcacheContent duplicate();
} }

View File

@ -42,4 +42,7 @@ public interface MemcacheContent extends MemcacheObject, ByteBufHolder {
@Override @Override
MemcacheContent touch(); MemcacheContent touch();
@Override
MemcacheContent touch(Object hint);
} }

View File

@ -36,4 +36,7 @@ public interface MemcacheMessage extends MemcacheObject, ReferenceCounted {
@Override @Override
MemcacheMessage touch(); MemcacheMessage touch();
@Override
MemcacheMessage touch(Object hint);
} }

View File

@ -110,8 +110,13 @@ public abstract class AbstractBinaryMemcacheMessage<H extends BinaryMemcacheMess
@Override @Override
public BinaryMemcacheMessage<H> touch() { public BinaryMemcacheMessage<H> touch() {
return touch(null);
}
@Override
public BinaryMemcacheMessage<H> touch(Object hint) {
if (extras != null) { if (extras != null) {
extras.touch(); extras.touch(hint);
} }
return this; return this;
} }

View File

@ -66,4 +66,7 @@ public interface BinaryMemcacheMessage<H extends BinaryMemcacheMessageHeader> ex
@Override @Override
BinaryMemcacheMessage<H> touch(); BinaryMemcacheMessage<H> touch();
@Override
BinaryMemcacheMessage<H> touch(Object hint);
} }

View File

@ -36,4 +36,7 @@ public interface BinaryMemcacheRequest extends BinaryMemcacheMessage<BinaryMemca
@Override @Override
BinaryMemcacheRequest touch(); BinaryMemcacheRequest touch();
@Override
BinaryMemcacheRequest touch(Object hint);
} }

View File

@ -36,4 +36,7 @@ public interface BinaryMemcacheResponse extends BinaryMemcacheMessage<BinaryMemc
@Override @Override
BinaryMemcacheResponse touch(); BinaryMemcacheResponse touch();
@Override
BinaryMemcacheResponse touch(Object hint);
} }

View File

@ -80,4 +80,10 @@ public class DefaultBinaryMemcacheRequest extends AbstractBinaryMemcacheMessage<
super.touch(); super.touch();
return this; return this;
} }
@Override
public BinaryMemcacheRequest touch(Object hint) {
super.touch(hint);
return this;
}
} }

View File

@ -80,4 +80,10 @@ public class DefaultBinaryMemcacheResponse extends AbstractBinaryMemcacheMessage
super.touch(); super.touch();
return this; return this;
} }
@Override
public BinaryMemcacheResponse touch(Object hint) {
super.touch(hint);
return this;
}
} }

View File

@ -83,6 +83,12 @@ public class DefaultFullBinaryMemcacheRequest extends DefaultBinaryMemcacheReque
return this; return this;
} }
@Override
public FullBinaryMemcacheRequest touch(Object hint) {
content.touch(hint);
return this;
}
@Override @Override
public boolean release() { public boolean release() {
return content.release(); return content.release();

View File

@ -83,6 +83,12 @@ public class DefaultFullBinaryMemcacheResponse extends DefaultBinaryMemcacheResp
return this; return this;
} }
@Override
public FullBinaryMemcacheResponse touch(Object hint) {
content.touch(hint);
return this;
}
@Override @Override
public boolean release() { public boolean release() {
return content.release(); return content.release();

View File

@ -34,6 +34,9 @@ public interface FullBinaryMemcacheRequest extends BinaryMemcacheRequest, FullMe
@Override @Override
FullBinaryMemcacheRequest touch(); FullBinaryMemcacheRequest touch();
@Override
FullBinaryMemcacheRequest touch(Object hint);
@Override @Override
FullBinaryMemcacheRequest duplicate(); FullBinaryMemcacheRequest duplicate();
} }

View File

@ -34,6 +34,9 @@ public interface FullBinaryMemcacheResponse extends BinaryMemcacheResponse, Full
@Override @Override
FullBinaryMemcacheResponse touch(); FullBinaryMemcacheResponse touch();
@Override
FullBinaryMemcacheResponse touch(Object hint);
@Override @Override
FullBinaryMemcacheResponse duplicate(); FullBinaryMemcacheResponse duplicate();
} }

View File

@ -978,6 +978,12 @@ final class ReplayingDecoderBuffer extends ByteBuf {
return this; return this;
} }
@Override
public ByteBuf touch(Object hint) {
buffer.touch(hint);
return this;
}
@Override @Override
public boolean release() { public boolean release() {
reject(); reject();

View File

@ -88,6 +88,11 @@ public abstract class AbstractReferenceCounted implements ReferenceCounted {
return this; return this;
} }
@Override
public ReferenceCounted touch() {
return touch(null);
}
@Override @Override
public final boolean release() { public final boolean release() {
for (;;) { for (;;) {

View File

@ -71,6 +71,19 @@ public final class ReferenceCountUtil {
return msg; return msg;
} }
/**
* Tries to call {@link ReferenceCounted#touch(Object)} if the specified message implements
* {@link ReferenceCounted}. If the specified message doesn't implement {@link ReferenceCounted},
* this method does nothing.
*/
@SuppressWarnings("unchecked")
public static <T> T touch(T msg, Object hint) {
if (msg instanceof ReferenceCounted) {
return (T) ((ReferenceCounted) msg).touch(hint);
}
return msg;
}
/** /**
* Try to call {@link ReferenceCounted#release()} if the specified message implements {@link ReferenceCounted}. * Try to call {@link ReferenceCounted#release()} if the specified message implements {@link ReferenceCounted}.
* If the specified message doesn't implement {@link ReferenceCounted}, this method does nothing. * If the specified message doesn't implement {@link ReferenceCounted}, this method does nothing.

View File

@ -48,10 +48,17 @@ public interface ReferenceCounted {
/** /**
* Records the current access location of this object for debugging purposes. * Records the current access location of this object for debugging purposes.
* If this object is determined to be leaked, the information recorded by this operation will be provided to you * If this object is determined to be leaked, the information recorded by this operation will be provided to you
* via {@link ResourceLeakDetector}. * via {@link ResourceLeakDetector}. This method is a shortcut to {@link #touch(Object) touch(null)}.
*/ */
ReferenceCounted touch(); ReferenceCounted touch();
/**
* Records the current access location of this object with an additonal arbitrary information for debugging
* purposes. If this object is determined to be leaked, the information recorded by this operation will be
* provided to you via {@link ResourceLeakDetector}.
*/
ReferenceCounted touch(Object hint);
/** /**
* Decreases the reference count by {@code 1} and deallocates this object if the reference count reaches at * Decreases the reference count by {@code 1} and deallocates this object if the reference count reaches at
* {@code 0}. * {@code 0}.

View File

@ -19,10 +19,16 @@ package io.netty.util;
public interface ResourceLeak { public interface ResourceLeak {
/** /**
* Records the caller's current stack trace so that the {@link ResourceLeakDetector} can tell where the leaked * Records the caller's current stack trace so that the {@link ResourceLeakDetector} can tell where the leaked
* resource was accessed lastly. * resource was accessed lastly. This method is a shortcut to {@link #record(Object) record(null)}.
*/ */
void record(); void record();
/**
* Records the caller's current stack trace and the specified additional arbitrary information
* so that the {@link ResourceLeakDetector} can tell where the leaked resource was accessed lastly.
*/
void record(Object hint);
/** /**
* Close the leak so that {@link ResourceLeakDetector} does not warn about leaked resources. * Close the leak so that {@link ResourceLeakDetector} does not warn about leaked resources.
* *

View File

@ -265,7 +265,7 @@ public final class ResourceLeakDetector<T> {
if (referent != null) { if (referent != null) {
Level level = getLevel(); Level level = getLevel();
if (level.ordinal() >= Level.ADVANCED.ordinal()) { if (level.ordinal() >= Level.ADVANCED.ordinal()) {
creationRecord = newRecord(3); creationRecord = newRecord(null, 3);
} else { } else {
creationRecord = null; creationRecord = null;
} }
@ -287,8 +287,17 @@ public final class ResourceLeakDetector<T> {
@Override @Override
public void record() { public void record() {
record0(null, 3);
}
@Override
public void record(Object hint) {
record0(hint, 3);
}
private void record0(Object hint, int recordsToSkip) {
if (creationRecord != null) { if (creationRecord != null) {
String value = newRecord(2); String value = newRecord(hint, recordsToSkip);
synchronized (lastRecords) { synchronized (lastRecords) {
int size = lastRecords.size(); int size = lastRecords.size();
@ -353,11 +362,27 @@ public final class ResourceLeakDetector<T> {
} }
private static final String[] STACK_TRACE_ELEMENT_EXCLUSIONS = { private static final String[] STACK_TRACE_ELEMENT_EXCLUSIONS = {
"io.netty.util.ReferenceCountUtil.touch(",
"io.netty.buffer.AdvancedLeakAwareByteBuf.touch(",
"io.netty.buffer.AbstractByteBufAllocator.toLeakAwareBuffer(", "io.netty.buffer.AbstractByteBufAllocator.toLeakAwareBuffer(",
}; };
static String newRecord(int recordsToSkip) { static String newRecord(Object hint, int recordsToSkip) {
StringBuilder buf = new StringBuilder(4096); StringBuilder buf = new StringBuilder(4096);
// Append the hint first if available.
if (hint != null) {
buf.append("\tHint: ");
// Prefer a hint string to a simple string form.
if (hint instanceof ResourceLeakHint) {
buf.append(((ResourceLeakHint) hint).toHintString());
} else {
buf.append(hint);
}
buf.append(NEWLINE);
}
// Append the stack trace.
StackTraceElement[] array = new Throwable().getStackTrace(); StackTraceElement[] array = new Throwable().getStackTrace();
for (StackTraceElement e: array) { for (StackTraceElement e: array) {
if (recordsToSkip > 0) { if (recordsToSkip > 0) {

View File

@ -0,0 +1,27 @@
/*
* Copyright 2014 The Netty Project
*
* The Netty Project licenses this file to you under the Apache License,
* version 2.0 (the "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at:
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*/
package io.netty.util;
/**
* A hint object that provides human-readable message for easier resource leak tracking.
*/
public interface ResourceLeakHint {
/**
* Returns a human-readable message that potentially enables easier resource leak tracking.
*/
String toHintString();
}

View File

@ -158,6 +158,12 @@ public final class SctpMessage extends DefaultByteBufHolder {
return this; return this;
} }
@Override
public SctpMessage touch(Object hint) {
super.touch(hint);
return this;
}
@Override @Override
public String toString() { public String toString() {
if (refCnt() == 0) { if (refCnt() == 0) {

View File

@ -58,4 +58,10 @@ public final class UdtMessage extends DefaultByteBufHolder {
super.touch(); super.touch();
return this; return this;
} }
@Override
public UdtMessage touch(Object hint) {
super.touch(hint);
return this;
}
} }

View File

@ -41,4 +41,16 @@ public interface AddressedEnvelope<M, A extends SocketAddress> extends Reference
* Returns the address of the recipient of this message. * Returns the address of the recipient of this message.
*/ */
A recipient(); A recipient();
@Override
AddressedEnvelope<M, A> retain();
@Override
AddressedEnvelope<M, A> retain(int increment);
@Override
AddressedEnvelope<M, A> touch();
@Override
AddressedEnvelope<M, A> touch(Object hint);
} }

View File

@ -108,6 +108,12 @@ public class DefaultAddressedEnvelope<M, A extends SocketAddress> implements Add
return this; return this;
} }
@Override
public AddressedEnvelope<M, A> touch(Object hint) {
ReferenceCountUtil.touch(message, hint);
return this;
}
@Override @Override
public String toString() { public String toString() {
if (sender != null) { if (sender != null) {

View File

@ -20,6 +20,7 @@ import io.netty.util.Attribute;
import io.netty.util.AttributeKey; import io.netty.util.AttributeKey;
import io.netty.util.Recycler; import io.netty.util.Recycler;
import io.netty.util.ReferenceCountUtil; import io.netty.util.ReferenceCountUtil;
import io.netty.util.ResourceLeakHint;
import io.netty.util.concurrent.EventExecutor; import io.netty.util.concurrent.EventExecutor;
import io.netty.util.concurrent.EventExecutorGroup; import io.netty.util.concurrent.EventExecutorGroup;
import io.netty.util.internal.StringUtil; import io.netty.util.internal.StringUtil;
@ -28,7 +29,7 @@ import java.net.SocketAddress;
import static io.netty.channel.DefaultChannelPipeline.*; import static io.netty.channel.DefaultChannelPipeline.*;
final class DefaultChannelHandlerContext implements ChannelHandlerContext { final class DefaultChannelHandlerContext implements ChannelHandlerContext, ResourceLeakHint {
volatile DefaultChannelHandlerContext next; volatile DefaultChannelHandlerContext next;
volatile DefaultChannelHandlerContext prev; volatile DefaultChannelHandlerContext prev;
@ -329,8 +330,8 @@ final class DefaultChannelHandlerContext implements ChannelHandlerContext {
throw new NullPointerException("msg"); throw new NullPointerException("msg");
} }
ReferenceCountUtil.touch(msg);
final DefaultChannelHandlerContext next = findContextInbound(); final DefaultChannelHandlerContext next = findContextInbound();
ReferenceCountUtil.touch(msg, next);
EventExecutor executor = next.executor(); EventExecutor executor = next.executor();
if (executor.inEventLoop()) { if (executor.inEventLoop()) {
next.invokeChannelRead(msg); next.invokeChannelRead(msg);
@ -706,8 +707,8 @@ final class DefaultChannelHandlerContext implements ChannelHandlerContext {
private void write(Object msg, boolean flush, ChannelPromise promise) { private void write(Object msg, boolean flush, ChannelPromise promise) {
ReferenceCountUtil.touch(msg);
DefaultChannelHandlerContext next = findContextOutbound(); DefaultChannelHandlerContext next = findContextOutbound();
ReferenceCountUtil.touch(msg, next);
EventExecutor executor = next.executor(); EventExecutor executor = next.executor();
if (executor.inEventLoop()) { if (executor.inEventLoop()) {
next.invokeWrite(msg, promise); next.invokeWrite(msg, promise);
@ -987,4 +988,14 @@ final class DefaultChannelHandlerContext implements ChannelHandlerContext {
RECYCLER.recycle(this, handle); RECYCLER.recycle(this, handle);
} }
} }
@Override
public String toHintString() {
return '\'' + name + "' will handle the message from this point.";
}
@Override
public String toString() {
return StringUtil.simpleClassName(ChannelHandlerContext.class) + '(' + name + ", " + channel + ')';
}
} }

View File

@ -121,4 +121,9 @@ public class DefaultFileRegion extends AbstractReferenceCounted implements FileR
public FileRegion touch() { public FileRegion touch() {
return this; return this;
} }
@Override
public FileRegion touch(Object hint) {
return this;
}
} }

View File

@ -89,4 +89,7 @@ public interface FileRegion extends ReferenceCounted {
@Override @Override
FileRegion touch(); FileRegion touch();
@Override
FileRegion touch(Object hint);
} }

View File

@ -69,4 +69,10 @@ public final class DatagramPacket
super.touch(); super.touch();
return this; return this;
} }
@Override
public DatagramPacket touch(Object hint) {
super.touch(hint);
return this;
}
} }

View File

@ -108,7 +108,7 @@ public class DefaultChannelPipelineTest {
} }
@Override @Override
public ReferenceCounted touch() { public ReferenceCounted touch(Object hint) {
return this; return this;
} }
}; };