惠合 v3.0.0版本的 MD5 值为:0eb47ffc7a53a6b708a3b4e3f9ed0e8c
以下内容为反编译后的 ResourceLeakDetector.java 源代码,内容仅作参考
package io.netty.util;
import com.google.android.exoplayer2.text.ttml.TtmlNode;
import io.netty.util.internal.EmptyArrays;
import io.netty.util.internal.ObjectUtil;
import io.netty.util.internal.PlatformDependent;
import io.netty.util.internal.StringUtil;
import io.netty.util.internal.SystemPropertyUtil;
import io.netty.util.internal.logging.InternalLogger;
import io.netty.util.internal.logging.InternalLoggerFactory;
import java.lang.ref.ReferenceQueue;
import java.lang.ref.WeakReference;
import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashSet;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicIntegerFieldUpdater;
import java.util.concurrent.atomic.AtomicReference;
import java.util.concurrent.atomic.AtomicReferenceFieldUpdater;
import p.a.y.e.a.s.e.net.r5;
public class ResourceLeakDetector<T> {
private static final Level DEFAULT_LEVEL;
private static final int DEFAULT_SAMPLING_INTERVAL = 128;
private static final int DEFAULT_TARGET_RECORDS = 4;
private static final String PROP_LEVEL = "io.netty.leakDetection.level";
private static final String PROP_LEVEL_OLD = "io.netty.leakDetectionLevel";
private static final String PROP_SAMPLING_INTERVAL = "io.netty.leakDetection.samplingInterval";
private static final String PROP_TARGET_RECORDS = "io.netty.leakDetection.targetRecords";
public static final int SAMPLING_INTERVAL;
private static final int TARGET_RECORDS;
private static final AtomicReference<String[]> excludedMethods;
private static Level level;
private static final InternalLogger logger;
private final Set<DefaultResourceLeak<?>> allLeaks;
private final ReferenceQueue<Object> refQueue;
private final Set<String> reportedLeaks;
private final String resourceType;
private final int samplingInterval;
public static final class DefaultResourceLeak<T> extends WeakReference<Object> implements ResourceLeakTracker<T>, ResourceLeak {
public static final boolean $assertionsDisabled = false;
private final Set<DefaultResourceLeak<?>> allLeaks;
private volatile int droppedRecords;
private volatile Record head;
private final int trackedHash;
private static final AtomicReferenceFieldUpdater<DefaultResourceLeak<?>, Record> headUpdater = AtomicReferenceFieldUpdater.newUpdater(DefaultResourceLeak.class, Record.class, TtmlNode.TAG_HEAD);
private static final AtomicIntegerFieldUpdater<DefaultResourceLeak<?>> droppedRecordsUpdater = AtomicIntegerFieldUpdater.newUpdater(DefaultResourceLeak.class, "droppedRecords");
public DefaultResourceLeak(Object obj, ReferenceQueue<Object> referenceQueue, Set<DefaultResourceLeak<?>> set) {
super(obj, referenceQueue);
this.trackedHash = System.identityHashCode(obj);
set.add(this);
headUpdater.set(this, new Record(Record.BOTTOM));
this.allLeaks = set;
}
private static void reachabilityFence0(Object obj) {
if (obj != null) {
synchronized (obj) {
}
}
}
private void record0(Object obj) {
AtomicReferenceFieldUpdater<DefaultResourceLeak<?>, Record> atomicReferenceFieldUpdater;
Record record;
boolean z;
Record record2;
if (ResourceLeakDetector.TARGET_RECORDS > 0) {
do {
atomicReferenceFieldUpdater = headUpdater;
record = atomicReferenceFieldUpdater.get(this);
if (record == null) {
return;
}
int i = record.pos + 1;
z = false;
if (i >= ResourceLeakDetector.TARGET_RECORDS) {
boolean z2 = PlatformDependent.threadLocalRandom().nextInt(1 << Math.min(i - ResourceLeakDetector.TARGET_RECORDS, 30)) != 0;
record2 = z2 ? record.next : record;
z = z2;
} else {
record2 = record;
}
} while (!atomicReferenceFieldUpdater.compareAndSet(this, record, obj != null ? new Record(record2, obj) : new Record(record2)));
if (z) {
droppedRecordsUpdater.incrementAndGet(this);
}
}
}
@Override
public boolean close() {
if (this.allLeaks.remove(this)) {
clear();
headUpdater.set(this, null);
return true;
}
return false;
}
@Override
public boolean close(T t) {
try {
return close();
} finally {
reachabilityFence0(t);
}
}
public boolean dispose() {
clear();
return this.allLeaks.remove(this);
}
@Override
public void record() {
record0(null);
}
@Override
public void record(Object obj) {
record0(obj);
}
public String toString() {
Record andSet = headUpdater.getAndSet(this, null);
if (andSet == null) {
return "";
}
int i = droppedRecordsUpdater.get(this);
int i2 = 0;
int i3 = 1;
int i4 = andSet.pos + 1;
StringBuilder sb = new StringBuilder(i4 * 2048);
String str = StringUtil.NEWLINE;
sb.append(str);
sb.append("Recent access records: ");
sb.append(str);
HashSet hashSet = new HashSet(i4);
while (andSet != Record.BOTTOM) {
String record = andSet.toString();
if (!hashSet.add(record)) {
i2++;
} else if (andSet.next == Record.BOTTOM) {
sb.append("Created at:");
sb.append(StringUtil.NEWLINE);
sb.append(record);
} else {
sb.append('#');
sb.append(i3);
sb.append(':');
sb.append(StringUtil.NEWLINE);
sb.append(record);
i3++;
}
andSet = andSet.next;
}
if (i2 > 0) {
sb.append(": ");
sb.append(i2);
sb.append(" leak records were discarded because they were duplicates");
sb.append(StringUtil.NEWLINE);
}
if (i > 0) {
sb.append(": ");
sb.append(i);
sb.append(" leak records were discarded because the leak record count is targeted to ");
sb.append(ResourceLeakDetector.TARGET_RECORDS);
sb.append(". Use system property ");
sb.append(ResourceLeakDetector.PROP_TARGET_RECORDS);
sb.append(" to increase the limit.");
sb.append(StringUtil.NEWLINE);
}
sb.setLength(sb.length() - StringUtil.NEWLINE.length());
return sb.toString();
}
}
public enum Level {
DISABLED,
SIMPLE,
ADVANCED,
PARANOID;
public static Level parseLevel(String str) {
String trim = str.trim();
Level[] values = values();
for (int i = 0; i < 4; i++) {
Level level = values[i];
if (trim.equalsIgnoreCase(level.name()) || trim.equals(String.valueOf(level.ordinal()))) {
return level;
}
}
return ResourceLeakDetector.DEFAULT_LEVEL;
}
}
public static final class Record extends Throwable {
private static final Record BOTTOM = new Record();
private static final long serialVersionUID = 6065153674892850720L;
private final String hintString;
private final Record next;
private final int pos;
private Record() {
this.hintString = null;
this.next = null;
this.pos = -1;
}
public Record(Record record) {
this.hintString = null;
this.next = record;
this.pos = record.pos + 1;
}
public Record(Record record, Object obj) {
this.hintString = obj instanceof ResourceLeakHint ? ((ResourceLeakHint) obj).toHintString() : obj.toString();
this.next = record;
this.pos = record.pos + 1;
}
@Override
public String toString() {
int i;
StringBuilder sb = new StringBuilder(2048);
if (this.hintString != null) {
sb.append("\tHint: ");
sb.append(this.hintString);
sb.append(StringUtil.NEWLINE);
}
StackTraceElement[] stackTrace = getStackTrace();
for (int i2 = 3; i2 < stackTrace.length; i2++) {
StackTraceElement stackTraceElement = stackTrace[i2];
String[] strArr = (String[]) ResourceLeakDetector.excludedMethods.get();
while (true) {
if (i >= strArr.length) {
sb.append('\t');
sb.append(stackTraceElement.toString());
sb.append(StringUtil.NEWLINE);
break;
}
i = (strArr[i].equals(stackTraceElement.getClassName()) && strArr[i + 1].equals(stackTraceElement.getMethodName())) ? 0 : i + 2;
}
}
return sb.toString();
}
}
static {
Level level2 = Level.SIMPLE;
DEFAULT_LEVEL = level2;
InternalLogger internalLoggerFactory = InternalLoggerFactory.getInstance(ResourceLeakDetector.class);
logger = internalLoggerFactory;
boolean z = false;
if (SystemPropertyUtil.get("io.netty.noResourceLeakDetection") != null) {
z = SystemPropertyUtil.getBoolean("io.netty.noResourceLeakDetection", false);
internalLoggerFactory.debug("-Dio.netty.noResourceLeakDetection: {}", Boolean.valueOf(z));
internalLoggerFactory.warn("-Dio.netty.noResourceLeakDetection is deprecated. Use '-D{}={}' instead.", PROP_LEVEL, level2.name().toLowerCase());
}
if (z) {
level2 = Level.DISABLED;
}
Level parseLevel = Level.parseLevel(SystemPropertyUtil.get(PROP_LEVEL, SystemPropertyUtil.get(PROP_LEVEL_OLD, level2.name())));
int i = SystemPropertyUtil.getInt(PROP_TARGET_RECORDS, 4);
TARGET_RECORDS = i;
SAMPLING_INTERVAL = SystemPropertyUtil.getInt(PROP_SAMPLING_INTERVAL, 128);
level = parseLevel;
if (internalLoggerFactory.isDebugEnabled()) {
internalLoggerFactory.debug("-D{}: {}", PROP_LEVEL, parseLevel.name().toLowerCase());
internalLoggerFactory.debug("-D{}: {}", PROP_TARGET_RECORDS, Integer.valueOf(i));
}
excludedMethods = new AtomicReference<>(EmptyArrays.EMPTY_STRINGS);
}
@Deprecated
public ResourceLeakDetector(Class<?> cls) {
this(StringUtil.simpleClassName(cls));
}
public ResourceLeakDetector(Class<?> cls, int i) {
this(StringUtil.simpleClassName(cls), i, Long.MAX_VALUE);
}
@Deprecated
public ResourceLeakDetector(Class<?> cls, int i, long j) {
this(cls, i);
}
@Deprecated
public ResourceLeakDetector(String str) {
this(str, 128, Long.MAX_VALUE);
}
@Deprecated
public ResourceLeakDetector(String str, int i, long j) {
this.allLeaks = Collections.newSetFromMap(new ConcurrentHashMap());
this.refQueue = new ReferenceQueue<>();
this.reportedLeaks = Collections.newSetFromMap(new ConcurrentHashMap());
this.resourceType = (String) ObjectUtil.checkNotNull(str, "resourceType");
this.samplingInterval = i;
}
public static void addExclusions(Class cls, String... strArr) {
String[] strArr2;
String[] strArr3;
HashSet hashSet = new HashSet(Arrays.asList(strArr));
Method[] declaredMethods = cls.getDeclaredMethods();
int length = declaredMethods.length;
for (int i = 0; i < length && (!hashSet.remove(declaredMethods[i].getName()) || !hashSet.isEmpty()); i++) {
}
if (!hashSet.isEmpty()) {
StringBuilder sb = new StringBuilder();
sb.append("Can't find '");
sb.append(hashSet);
sb.append("' in ");
throw new IllegalArgumentException(r5.lite_break(cls, sb));
}
do {
strArr2 = excludedMethods.get();
strArr3 = (String[]) Arrays.copyOf(strArr2, (strArr.length * 2) + strArr2.length);
for (int i2 = 0; i2 < strArr.length; i2++) {
int i3 = i2 * 2;
strArr3[strArr2.length + i3] = cls.getName();
strArr3[strArr2.length + i3 + 1] = strArr[i2];
}
} while (!excludedMethods.compareAndSet(strArr2, strArr3));
}
private void clearRefQueue() {
while (true) {
DefaultResourceLeak defaultResourceLeak = (DefaultResourceLeak) this.refQueue.poll();
if (defaultResourceLeak == null) {
return;
}
defaultResourceLeak.dispose();
}
}
public static Level getLevel() {
return level;
}
public static boolean isEnabled() {
int ordinal = getLevel().ordinal();
Level level2 = Level.DISABLED;
return ordinal > 0;
}
private void reportLeak() {
if (!needReport()) {
clearRefQueue();
return;
}
while (true) {
DefaultResourceLeak defaultResourceLeak = (DefaultResourceLeak) this.refQueue.poll();
if (defaultResourceLeak == null) {
return;
}
if (defaultResourceLeak.dispose()) {
String defaultResourceLeak2 = defaultResourceLeak.toString();
if (this.reportedLeaks.add(defaultResourceLeak2)) {
if (defaultResourceLeak2.isEmpty()) {
reportUntracedLeak(this.resourceType);
} else {
reportTracedLeak(this.resourceType, defaultResourceLeak2);
}
}
}
}
}
@Deprecated
public static void setEnabled(boolean z) {
setLevel(z ? Level.SIMPLE : Level.DISABLED);
}
public static void setLevel(Level level2) {
level = (Level) ObjectUtil.checkNotNull(level2, "level");
}
private DefaultResourceLeak track0(T t) {
Level level2 = level;
if (level2 == Level.DISABLED) {
return null;
}
int ordinal = level2.ordinal();
Level level3 = Level.PARANOID;
if (ordinal >= 3) {
reportLeak();
return new DefaultResourceLeak(t, this.refQueue, this.allLeaks);
} else if (PlatformDependent.threadLocalRandom().nextInt(this.samplingInterval) == 0) {
reportLeak();
return new DefaultResourceLeak(t, this.refQueue, this.allLeaks);
} else {
return null;
}
}
public boolean needReport() {
return logger.isErrorEnabled();
}
@Deprecated
public final ResourceLeak open(T t) {
return track0(t);
}
@Deprecated
public void reportInstancesLeak(String str) {
}
public void reportTracedLeak(String str, String str2) {
logger.error("LEAK: {}.release() was not called before it's garbage-collected. See https://netty.io/wiki/reference-counted-objects.html for more information.{}", str, str2);
}
public void reportUntracedLeak(String str) {
logger.error("LEAK: {}.release() was not called before it's garbage-collected. Enable advanced leak reporting to find out where the leak occurred. To enable advanced leak reporting, specify the JVM option '-D{}={}' or call {}.setLevel() See https://netty.io/wiki/reference-counted-objects.html for more information.", str, PROP_LEVEL, Level.ADVANCED.name().toLowerCase(), StringUtil.simpleClassName(this));
}
public final ResourceLeakTracker<T> track(T t) {
return track0(t);
}
}