1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.eclipse.jetty.io;
20
21 import java.nio.ByteBuffer;
22 import java.util.concurrent.atomic.AtomicLong;
23
24 import org.eclipse.jetty.util.BufferUtil;
25 import org.eclipse.jetty.util.LeakDetector;
26 import org.eclipse.jetty.util.component.ContainerLifeCycle;
27 import org.eclipse.jetty.util.log.Log;
28 import org.eclipse.jetty.util.log.Logger;
29
30 public class LeakTrackingByteBufferPool extends ContainerLifeCycle implements ByteBufferPool
31 {
32 private static final Logger LOG = Log.getLogger(LeakTrackingByteBufferPool.class);
33
34 private final LeakDetector<ByteBuffer> leakDetector = new LeakDetector<ByteBuffer>()
35 {
36 public String id(ByteBuffer resource)
37 {
38 return BufferUtil.toIDString(resource);
39 }
40
41 @Override
42 protected void leaked(LeakInfo leakInfo)
43 {
44 leaked.incrementAndGet();
45 LeakTrackingByteBufferPool.this.leaked(leakInfo);
46 }
47 };
48
49 private final static boolean NOISY = Boolean.getBoolean(LeakTrackingByteBufferPool.class.getName() + ".NOISY");
50 private final ByteBufferPool delegate;
51 private final AtomicLong leakedReleases = new AtomicLong(0);
52 private final AtomicLong leakedAcquires = new AtomicLong(0);
53 private final AtomicLong leaked = new AtomicLong(0);
54
55 public LeakTrackingByteBufferPool(ByteBufferPool delegate)
56 {
57 this.delegate = delegate;
58 addBean(leakDetector);
59 addBean(delegate);
60 }
61
62 @Override
63 public ByteBuffer acquire(int size, boolean direct)
64 {
65 ByteBuffer buffer = delegate.acquire(size, direct);
66 boolean leaked = leakDetector.acquired(buffer);
67 if (NOISY || !leaked)
68 {
69 leakedAcquires.incrementAndGet();
70 LOG.info(String.format("ByteBuffer acquire %s leaked.acquired=%s", leakDetector.id(buffer), leaked ? "normal" : "LEAK"),
71 new Throwable("LeakStack.Acquire"));
72 }
73 return buffer;
74 }
75
76 @Override
77 public void release(ByteBuffer buffer)
78 {
79 if (buffer == null)
80 return;
81 boolean leaked = leakDetector.released(buffer);
82 if (NOISY || !leaked)
83 {
84 leakedReleases.incrementAndGet();
85 LOG.info(String.format("ByteBuffer release %s leaked.released=%s", leakDetector.id(buffer), leaked ? "normal" : "LEAK"), new Throwable(
86 "LeakStack.Release"));
87 }
88 delegate.release(buffer);
89 }
90
91 public void clearTracking()
92 {
93 leakedAcquires.set(0);
94 leakedReleases.set(0);
95 }
96
97
98
99
100 public long getLeakedAcquires()
101 {
102 return leakedAcquires.get();
103 }
104
105
106
107
108 public long getLeakedReleases()
109 {
110 return leakedReleases.get();
111 }
112
113
114
115
116 public long getLeakedResources()
117 {
118 return leaked.get();
119 }
120
121 protected void leaked(LeakDetector<ByteBuffer>.LeakInfo leakInfo)
122 {
123 LOG.warn("ByteBuffer " + leakInfo.getResourceDescription() + " leaked at:", leakInfo.getStackFrames());
124 }
125 }