Leak Detector disclosing when records dropped

Motivation:
ResourceLeakDetector enforces a limit as to how large the queue is allowed to grow for stack traces in order to keep memory from growing too large. However it is not always clear when records are dropped, or how many have been dropped. This can make interpreting leak reports more difficult if you assume all information is present when it may not be. Also we should increase the limit (currently 4) when running tests on the CI servers.

Modifications:
- Increase leak detector record limit on CI servers from 4 to 32.
- Track how many records have been discarded and disclose this in the leak report.

Result:
Leak reports clarify how many records were dropped, and how to increase the limit.
This commit is contained in:
Scott Mitchell 2016-02-10 09:42:58 -08:00
parent 691bc1690e
commit fdc6a5e87f
2 changed files with 23 additions and 8 deletions

View File

@ -30,7 +30,9 @@ import java.util.EnumSet;
import java.util.concurrent.ConcurrentMap; import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicBoolean;
import static io.netty.util.internal.StringUtil.*; import static io.netty.util.internal.StringUtil.EMPTY_STRING;
import static io.netty.util.internal.StringUtil.NEWLINE;
import static io.netty.util.internal.StringUtil.simpleClassName;
public final class ResourceLeakDetector<T> { public final class ResourceLeakDetector<T> {
@ -276,6 +278,7 @@ public final class ResourceLeakDetector<T> {
private final AtomicBoolean freed; private final AtomicBoolean freed;
private DefaultResourceLeak prev; private DefaultResourceLeak prev;
private DefaultResourceLeak next; private DefaultResourceLeak next;
private int removedRecords;
DefaultResourceLeak(Object referent) { DefaultResourceLeak(Object referent) {
super(referent, referent != null? refQueue : null); super(referent, referent != null? refQueue : null);
@ -324,6 +327,7 @@ public final class ResourceLeakDetector<T> {
} }
if (size > MAX_RECORDS) { if (size > MAX_RECORDS) {
lastRecords.removeFirst(); lastRecords.removeFirst();
++removedRecords;
} }
} }
} }
@ -347,19 +351,30 @@ public final class ResourceLeakDetector<T> {
@Override @Override
public String toString() { public String toString() {
if (creationRecord == null) { if (creationRecord == null) {
return ""; return EMPTY_STRING;
} }
Object[] array; final Object[] array;
final int removedRecords;
synchronized (lastRecords) { synchronized (lastRecords) {
array = lastRecords.toArray(); array = lastRecords.toArray();
removedRecords = this.removedRecords;
} }
StringBuilder buf = new StringBuilder(16384) StringBuilder buf = new StringBuilder(16384).append(NEWLINE);
.append(NEWLINE) if (removedRecords > 0) {
.append("Recent access records: ") buf.append("WARNING: ")
.append(array.length) .append(removedRecords)
.append(" leak records were discarded because the leak record count is limited to ")
.append(MAX_RECORDS)
.append(". Use system property ")
.append(PROP_MAX_RECORDS)
.append(" to increase the limit.")
.append(NEWLINE); .append(NEWLINE);
}
buf.append("Recent access records: ")
.append(array.length)
.append(NEWLINE);
if (array.length > 0) { if (array.length > 0) {
for (int i = array.length - 1; i >= 0; i --) { for (int i = array.length - 1; i >= 0; i --) {

View File

@ -71,7 +71,7 @@
<profile> <profile>
<id>leak</id> <id>leak</id>
<properties> <properties>
<argLine.leak>-Dio.netty.leakDetectionLevel=paranoid</argLine.leak> <argLine.leak>-Dio.netty.leakDetectionLevel=paranoid -Dio.netty.leakDetection.maxRecord=32</argLine.leak>
</properties> </properties>
</profile> </profile>
<profile> <profile>