Merge pull request #619 from DataDog/mar-kolya/fix-memory-leak-in-weak-map

Mar kolya/fix memory leak in weak map
This commit is contained in:
Nikolay Martynov 2018-12-05 17:32:42 -05:00 committed by GitHub
commit 44aadf36ce
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 29 additions and 12 deletions

View File

@ -54,7 +54,7 @@ class WeakMapSuppliers {
};
private final ScheduledExecutorService cleanerExecutorService;
private final Thread shutdownCallback;
private final Queue<WeakReference<WeakConcurrentMap>> suppliedMaps =
new ConcurrentLinkedQueue<>();
@ -62,14 +62,16 @@ class WeakMapSuppliers {
WeakConcurrent() {
cleanerExecutorService = Executors.newScheduledThreadPool(1, THREAD_FACTORY);
shutdownCallback = new ShutdownCallback(cleanerExecutorService);
cleanerExecutorService.scheduleAtFixedRate(
new CleanupRunnable(cleanerExecutorService, suppliedMaps, finalized),
new CleanupRunnable(cleanerExecutorService, shutdownCallback, suppliedMaps, finalized),
CLEAN_FREQUENCY_SECONDS,
CLEAN_FREQUENCY_SECONDS,
TimeUnit.SECONDS);
try {
Runtime.getRuntime().addShutdownHook(new ShutdownCallback(cleanerExecutorService));
Runtime.getRuntime().addShutdownHook(shutdownCallback);
} catch (final IllegalStateException ex) {
// The JVM is already shutting down.
}
@ -90,14 +92,17 @@ class WeakMapSuppliers {
private static class CleanupRunnable implements Runnable {
private final ScheduledExecutorService executorService;
private final Thread shutdownCallback;
private final Queue<WeakReference<WeakConcurrentMap>> suppliedMaps;
private final AtomicBoolean finalized;
public CleanupRunnable(
final ScheduledExecutorService executorService,
final Thread shutdownCallback,
final Queue<WeakReference<WeakConcurrentMap>> suppliedMaps,
final AtomicBoolean finalized) {
this.executorService = executorService;
this.shutdownCallback = shutdownCallback;
this.suppliedMaps = suppliedMaps;
this.finalized = finalized;
}
@ -115,6 +120,7 @@ class WeakMapSuppliers {
}
if (finalized.get() && suppliedMaps.isEmpty()) {
executorService.shutdown();
Runtime.getRuntime().removeShutdownHook(shutdownCallback);
}
}
}

View File

@ -107,7 +107,7 @@ class WeakConcurrentSupplierTest extends Specification {
// Hit map a few times to trigger unreferenced entries cleanup.
// Exact number of times that we need to hit map is implementation dependent.
// For Guava it i specified in
// For Guava it is specified in
// com.google.common.collect.MapMakerInternalMap.DRAIN_THRESHOLD = 0x3F
if (name == "Guava" || name == "WeakInline") {
for (int i = 0; i <= 0x3F; i++) {

View File

@ -60,6 +60,11 @@ public class DDTracer implements io.opentracing.Tracer, Closeable, datadog.trace
private final Map<String, String> defaultSpanTags;
/** A configured mapping of service names to update with new values */
private final Map<String, String> serviceNameMappings;
/**
* JVM shutdown callback, keeping a reference to it to remove this if DDTracer gets destroyed
* earlier
*/
private final Thread shutdownCallback;
/** Span context decorators */
private final Map<String, List<AbstractDecorator>> spanContextDecorators =
@ -163,15 +168,15 @@ public class DDTracer implements io.opentracing.Tracer, Closeable, datadog.trace
this.runtimeId = runtimeId;
this.serviceNameMappings = serviceNameMappings;
shutdownCallback =
new Thread() {
@Override
public void run() {
close();
}
};
try {
Runtime.getRuntime()
.addShutdownHook(
new Thread() {
@Override
public void run() {
close();
}
});
Runtime.getRuntime().addShutdownHook(shutdownCallback);
} catch (final IllegalStateException ex) {
// The JVM is already shutting down.
}
@ -200,6 +205,12 @@ public class DDTracer implements io.opentracing.Tracer, Closeable, datadog.trace
log.info("New instance: {}", this);
}
@Override
public void finalize() {
Runtime.getRuntime().removeShutdownHook(shutdownCallback);
shutdownCallback.run();
}
/**
* Returns the list of span context decorators
*