1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package io.netty5.buffer.api;
17
18 import io.netty5.util.internal.logging.InternalLogger;
19 import io.netty5.util.internal.logging.InternalLoggerFactory;
20
21 import java.util.function.Consumer;
22
23
24
25
26
27
28
29
30
31 public final class LoggingLeakCallback implements Consumer<LeakInfo> {
32 private static final InternalLogger logger = InternalLoggerFactory.getInstance(LoggingLeakCallback.class);
33 private static final LoggingLeakCallback instance = new LoggingLeakCallback();
34
35
36
37
38
39
40 public static LoggingLeakCallback getInstance() {
41 return instance;
42 }
43
44 private LoggingLeakCallback() {
45 }
46
47 @Override
48 public void accept(LeakInfo leakInfo) {
49 if (logger.isErrorEnabled()) {
50 String message = "LEAK: Object \"" + leakInfo.objectDescription() + "\" was not property closed before " +
51 "it was garbage collected. " +
52 "A life-cycle back-trace (if any) is attached as suppressed exceptions. " +
53 "See https://netty.io/wiki/reference-counted-objects.html for more information.";
54 logger.error(message, LeakReport.reportFor(leakInfo));
55 }
56 }
57
58 private static final class LeakReport extends Throwable {
59 private static final long serialVersionUID = -1894217374238341652L;
60
61 static LeakReport reportFor(LeakInfo info) {
62 LeakReport report = new LeakReport();
63 info.forEach(tracePoint -> report.addSuppressed(tracePoint.traceback()));
64 return report;
65 }
66
67 private LeakReport() {
68 super("Object life-cycle trace:", null, true, false);
69 }
70 }
71 }