Remove deprecated stuff around ResourceLeakDetector (#11572)

Motivation:
A number of classes and APIs around the ResourceLeakDetector have been deprecated for removal in Netty 5.x, because better alternatives exist.

Modification:
Remove everything in and around ResourceLeakDetector that is deprecated, and fix the few usages that were found.

Result:
Less deprecated code.
This commit is contained in:
Chris Vest 2021-08-11 21:41:49 +02:00 committed by GitHub
parent 11fcfe1f73
commit a3d5617d45
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 22 additions and 267 deletions

View File

@ -1,42 +0,0 @@
/*
* Copyright 2013 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:
*
* https://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;
/**
* @deprecated please use {@link ResourceLeakTracker} as it may lead to false-positives.
*/
@Deprecated
public interface ResourceLeak {
/**
* Records the caller's current stack trace so that the {@link ResourceLeakDetector} can tell where the leaked
* resource was accessed lastly. This method is a shortcut to {@link #record(Object) record(null)}.
*/
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.
*
* @return {@code true} if called first time, {@code false} if called already
*/
boolean close();
}

View File

@ -114,14 +114,6 @@ public class ResourceLeakDetector<T> {
} }
} }
/**
* @deprecated Use {@link #setLevel(Level)} instead.
*/
@Deprecated
public static void setEnabled(boolean enabled) {
setLevel(enabled? Level.SIMPLE : Level.DISABLED);
}
/** /**
* Returns {@code true} if resource leak detection is enabled. * Returns {@code true} if resource leak detection is enabled.
*/ */
@ -154,70 +146,15 @@ public class ResourceLeakDetector<T> {
private final int samplingInterval; private final int samplingInterval;
/** /**
* @deprecated use {@link ResourceLeakDetectorFactory#newResourceLeakDetector(Class, int, long)}.
*/
@Deprecated
public ResourceLeakDetector(Class<?> resourceType) {
this(simpleClassName(resourceType));
}
/**
* @deprecated use {@link ResourceLeakDetectorFactory#newResourceLeakDetector(Class, int, long)}.
*/
@Deprecated
public ResourceLeakDetector(String resourceType) {
this(resourceType, DEFAULT_SAMPLING_INTERVAL, Long.MAX_VALUE);
}
/**
* @deprecated Use {@link ResourceLeakDetector#ResourceLeakDetector(Class, int)}.
* <p>
* This should not be used directly by users of {@link ResourceLeakDetector}. * This should not be used directly by users of {@link ResourceLeakDetector}.
* Please use {@link ResourceLeakDetectorFactory#newResourceLeakDetector(Class)} * Please use {@link ResourceLeakDetectorFactory#newResourceLeakDetector(Class)}
* or {@link ResourceLeakDetectorFactory#newResourceLeakDetector(Class, int, long)} * or {@link ResourceLeakDetectorFactory#newResourceLeakDetector(Class, int)}
*
* @param maxActive This is deprecated and will be ignored.
*/ */
@Deprecated
public ResourceLeakDetector(Class<?> resourceType, int samplingInterval, long maxActive) {
this(resourceType, samplingInterval);
}
/**
* This should not be used directly by users of {@link ResourceLeakDetector}.
* Please use {@link ResourceLeakDetectorFactory#newResourceLeakDetector(Class)}
* or {@link ResourceLeakDetectorFactory#newResourceLeakDetector(Class, int, long)}
*/
@SuppressWarnings("deprecation")
public ResourceLeakDetector(Class<?> resourceType, int samplingInterval) { public ResourceLeakDetector(Class<?> resourceType, int samplingInterval) {
this(simpleClassName(resourceType), samplingInterval, Long.MAX_VALUE); this.resourceType = simpleClassName(resourceType);
}
/**
* @deprecated use {@link ResourceLeakDetectorFactory#newResourceLeakDetector(Class, int, long)}.
* <p>
* @param maxActive This is deprecated and will be ignored.
*/
@Deprecated
public ResourceLeakDetector(String resourceType, int samplingInterval, long maxActive) {
requireNonNull(resourceType, "resourceType");
this.resourceType = resourceType;
this.samplingInterval = samplingInterval; this.samplingInterval = samplingInterval;
} }
/**
* Creates a new {@link ResourceLeak} which is expected to be closed via {@link ResourceLeak#close()} when the
* related resource is deallocated.
*
* @return the {@link ResourceLeak} or {@code null}
* @deprecated use {@link #track(Object)}
*/
@Deprecated
public final ResourceLeak open(T obj) {
return track0(obj);
}
/** /**
* Creates a new {@link ResourceLeakTracker} which is expected to be closed via * Creates a new {@link ResourceLeakTracker} which is expected to be closed via
* {@link ResourceLeakTracker#close(Object)} when the related resource is deallocated. * {@link ResourceLeakTracker#close(Object)} when the related resource is deallocated.
@ -326,9 +263,8 @@ public class ResourceLeakDetector<T> {
protected void reportInstancesLeak(String resourceType) { protected void reportInstancesLeak(String resourceType) {
} }
@SuppressWarnings("deprecation")
private static final class DefaultResourceLeak<T> private static final class DefaultResourceLeak<T>
extends WeakReference<Object> implements ResourceLeakTracker<T>, ResourceLeak { extends WeakReference<Object> implements ResourceLeakTracker<T> {
@SuppressWarnings("unchecked") // generics and updaters do not mix. @SuppressWarnings("unchecked") // generics and updaters do not mix.
private static final AtomicReferenceFieldUpdater<DefaultResourceLeak<?>, TraceRecord> headUpdater = private static final AtomicReferenceFieldUpdater<DefaultResourceLeak<?>, TraceRecord> headUpdater =
@ -438,7 +374,11 @@ public class ResourceLeakDetector<T> {
} }
@Override @Override
public boolean close() { public boolean close(T trackedObject) {
// Ensure that the object that was tracked is the same as the one that was passed to close(...).
assert trackedHash == System.identityHashCode(trackedObject);
try {
if (allLeaks.remove(this)) { if (allLeaks.remove(this)) {
// Call clear so the reference is not even enqueued. // Call clear so the reference is not even enqueued.
clear(); clear();
@ -446,15 +386,6 @@ public class ResourceLeakDetector<T> {
return true; return true;
} }
return false; return false;
}
@Override
public boolean close(T trackedObject) {
// Ensure that the object that was tracked is the same as the one that was passed to close(...).
assert trackedHash == System.identityHashCode(trackedObject);
try {
return close();
} finally { } finally {
// Ensure the tracked object remain live and strongly referenced, until close() has finished. // Ensure the tracked object remain live and strongly referenced, until close() has finished.
Reference.reachabilityFence(trackedObject); Reference.reachabilityFence(trackedObject);
@ -518,7 +449,7 @@ public class ResourceLeakDetector<T> {
private static final AtomicReference<String[]> excludedMethods = private static final AtomicReference<String[]> excludedMethods =
new AtomicReference<>(EmptyArrays.EMPTY_STRINGS); new AtomicReference<>(EmptyArrays.EMPTY_STRINGS);
public static void addExclusions(Class clz, String ... methodNames) { public static void addExclusions(Class<?> clz, String ... methodNames) {
Set<String> nameSet = new HashSet<>(Arrays.asList(methodNames)); Set<String> nameSet = new HashSet<>(Arrays.asList(methodNames));
// Use loop rather than lookup. This avoids knowing the parameters, and doesn't have to handle // Use loop rather than lookup. This avoids knowing the parameters, and doesn't have to handle
// NoSuchMethodException. // NoSuchMethodException.

View File

@ -66,39 +66,20 @@ public abstract class ResourceLeakDetectorFactory {
} }
/** /**
* @deprecated Use {@link #newResourceLeakDetector(Class, int)} instead.
* <p>
* Returns a new instance of a {@link ResourceLeakDetector} with the given resource class. * Returns a new instance of a {@link ResourceLeakDetector} with the given resource class.
* *
* @param resource the resource class used to initialize the {@link ResourceLeakDetector} * @param resource the resource class used to initialize the {@link ResourceLeakDetector}
* @param samplingInterval the interval on which sampling takes place * @param samplingInterval the interval on which sampling takes place
* @param maxActive This is deprecated and will be ignored.
* @param <T> the type of the resource class * @param <T> the type of the resource class
* @return a new instance of {@link ResourceLeakDetector} * @return a new instance of {@link ResourceLeakDetector}
*/ */
@Deprecated
public abstract <T> ResourceLeakDetector<T> newResourceLeakDetector( public abstract <T> ResourceLeakDetector<T> newResourceLeakDetector(
Class<T> resource, int samplingInterval, long maxActive); Class<T> resource, int samplingInterval);
/**
* Returns a new instance of a {@link ResourceLeakDetector} with the given resource class.
*
* @param resource the resource class used to initialize the {@link ResourceLeakDetector}
* @param samplingInterval the interval on which sampling takes place
* @param <T> the type of the resource class
* @return a new instance of {@link ResourceLeakDetector}
*/
@SuppressWarnings("deprecation")
public <T> ResourceLeakDetector<T> newResourceLeakDetector(Class<T> resource, int samplingInterval) {
ObjectUtil.checkPositive(samplingInterval, "samplingInterval");
return newResourceLeakDetector(resource, samplingInterval, Long.MAX_VALUE);
}
/** /**
* Default implementation that loads custom leak detector via system property * Default implementation that loads custom leak detector via system property
*/ */
private static final class DefaultResourceLeakDetectorFactory extends ResourceLeakDetectorFactory { private static final class DefaultResourceLeakDetectorFactory extends ResourceLeakDetectorFactory {
private final Constructor<?> obsoleteCustomClassConstructor;
private final Constructor<?> customClassConstructor; private final Constructor<?> customClassConstructor;
DefaultResourceLeakDetectorFactory() { DefaultResourceLeakDetectorFactory() {
@ -110,30 +91,12 @@ public abstract class ResourceLeakDetectorFactory {
customLeakDetector = null; customLeakDetector = null;
} }
if (customLeakDetector == null) { if (customLeakDetector == null) {
obsoleteCustomClassConstructor = customClassConstructor = null; customClassConstructor = null;
} else { } else {
obsoleteCustomClassConstructor = obsoleteCustomClassConstructor(customLeakDetector);
customClassConstructor = customClassConstructor(customLeakDetector); customClassConstructor = customClassConstructor(customLeakDetector);
} }
} }
private static Constructor<?> obsoleteCustomClassConstructor(String customLeakDetector) {
try {
final Class<?> detectorClass = Class.forName(customLeakDetector, true,
PlatformDependent.getSystemClassLoader());
if (ResourceLeakDetector.class.isAssignableFrom(detectorClass)) {
return detectorClass.getConstructor(Class.class, int.class, long.class);
} else {
logger.error("Class {} does not inherit from ResourceLeakDetector.", customLeakDetector);
}
} catch (Throwable t) {
logger.error("Could not load custom resource leak detector class provided: {}",
customLeakDetector, t);
}
return null;
}
private static Constructor<?> customClassConstructor(String customLeakDetector) { private static Constructor<?> customClassConstructor(String customLeakDetector) {
try { try {
final Class<?> detectorClass = Class.forName(customLeakDetector, true, final Class<?> detectorClass = Class.forName(customLeakDetector, true,
@ -151,34 +114,9 @@ public abstract class ResourceLeakDetectorFactory {
return null; return null;
} }
@SuppressWarnings("deprecation")
@Override
public <T> ResourceLeakDetector<T> newResourceLeakDetector(Class<T> resource, int samplingInterval,
long maxActive) {
if (obsoleteCustomClassConstructor != null) {
try {
@SuppressWarnings("unchecked")
ResourceLeakDetector<T> leakDetector =
(ResourceLeakDetector<T>) obsoleteCustomClassConstructor.newInstance(
resource, samplingInterval, maxActive);
logger.debug("Loaded custom ResourceLeakDetector: {}",
obsoleteCustomClassConstructor.getDeclaringClass().getName());
return leakDetector;
} catch (Throwable t) {
logger.error(
"Could not load custom resource leak detector provided: {} with the given resource: {}",
obsoleteCustomClassConstructor.getDeclaringClass().getName(), resource, t);
}
}
ResourceLeakDetector<T> resourceLeakDetector = new ResourceLeakDetector<>(resource, samplingInterval,
maxActive);
logger.debug("Loaded default ResourceLeakDetector: {}", resourceLeakDetector);
return resourceLeakDetector;
}
@Override @Override
public <T> ResourceLeakDetector<T> newResourceLeakDetector(Class<T> resource, int samplingInterval) { public <T> ResourceLeakDetector<T> newResourceLeakDetector(Class<T> resource, int samplingInterval) {
ObjectUtil.checkPositive(samplingInterval, "samplingInterval");
if (customClassConstructor != null) { if (customClassConstructor != null) {
try { try {
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")

View File

@ -1,70 +0,0 @@
/*
* Copyright 2013 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:
*
* https://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;
import java.util.Arrays;
/**
* @deprecated This class will be removed in the future version.
*/
@Deprecated
public class ResourceLeakException extends RuntimeException {
private static final long serialVersionUID = 7186453858343358280L;
private final StackTraceElement[] cachedStackTrace;
public ResourceLeakException() {
cachedStackTrace = getStackTrace();
}
public ResourceLeakException(String message) {
super(message);
cachedStackTrace = getStackTrace();
}
public ResourceLeakException(String message, Throwable cause) {
super(message, cause);
cachedStackTrace = getStackTrace();
}
public ResourceLeakException(Throwable cause) {
super(cause);
cachedStackTrace = getStackTrace();
}
@Override
public int hashCode() {
int hashCode = 0;
for (StackTraceElement e: cachedStackTrace) {
hashCode = hashCode * 31 + e.hashCode();
}
return hashCode;
}
@Override
public boolean equals(Object o) {
if (!(o instanceof ResourceLeakException)) {
return false;
}
if (o == this) {
return true;
}
return Arrays.equals(cachedStackTrace, ((ResourceLeakException) o).cachedStackTrace);
}
}

View File

@ -76,8 +76,8 @@ public class ResourceLeakDetectorTest {
} }
boolean closed = r.close(); boolean closed = r.close();
if (checkClosed && !closed) { if (checkClosed && !closed) {
error.compareAndSet(null, error.compareAndSet(null, new AssertionError(
new AssertionError("ResourceLeak.close() returned 'false' but expected 'true'")); "ResourceLeakTracker.close() returned 'false' but expected 'true'"));
return true; return true;
} }
} }
@ -121,8 +121,7 @@ public class ResourceLeakDetectorTest {
private static final class DefaultResource implements Resource { private static final class DefaultResource implements Resource {
// Sample every allocation // Sample every allocation
static final TestResourceLeakDetector<Resource> detector = new TestResourceLeakDetector<>( static final TestResourceLeakDetector<Resource> detector = new TestResourceLeakDetector<>(Resource.class, 1);
Resource.class, 1, Integer.MAX_VALUE);
@Override @Override
public boolean close() { public boolean close() {
@ -145,8 +144,8 @@ public class ResourceLeakDetectorTest {
private final AtomicReference<Throwable> error = new AtomicReference<>(); private final AtomicReference<Throwable> error = new AtomicReference<>();
TestResourceLeakDetector(Class<?> resourceType, int samplingInterval, long maxActive) { TestResourceLeakDetector(Class<?> resourceType, int samplingInterval) {
super(resourceType, samplingInterval, maxActive); super(resourceType, samplingInterval);
} }
@Override @Override

View File

@ -26,11 +26,11 @@ public class ResourceLeakDetectorBenchmark extends AbstractMicrobenchmark {
@Setup @Setup
public void setup() { public void setup() {
detector = new ResourceLeakDetector<>(getClass(), 128, Long.MAX_VALUE); detector = new ResourceLeakDetector<>(getClass(), 128);
} }
@Benchmark @Benchmark
public Object open() { public Object open() {
return detector.open(DUMMY); return detector.track(DUMMY);
} }
} }

View File

@ -32,8 +32,7 @@ public class ResourceLeakDetectorRecordBenchmark extends AbstractMicrobenchmark
private int recordTimes; private int recordTimes;
private ResourceLeakDetector.Level level; private ResourceLeakDetector.Level level;
ResourceLeakDetector<Object> detector = new ResourceLeakDetector<Object>( ResourceLeakDetector<Object> detector = new ResourceLeakDetector<Object>(Object.class, 1) {
Object.class, 1, Integer.MAX_VALUE) {
@Override @Override
protected void reportTracedLeak(String resourceType, String records) { protected void reportTracedLeak(String resourceType, String records) {
// noop // noop