1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package io.netty.buffer;
17
18 import io.netty.util.internal.CleanableDirectBuffer;
19 import io.netty.util.internal.PlatformDependent;
20 import io.netty.util.internal.StringUtil;
21
22 import java.nio.ByteBuffer;
23 import java.util.concurrent.atomic.LongAdder;
24
25
26
27
28 public final class UnpooledByteBufAllocator extends AbstractByteBufAllocator implements ByteBufAllocatorMetricProvider {
29
30 private final UnpooledByteBufAllocatorMetric metric = new UnpooledByteBufAllocatorMetric();
31 private final boolean disableLeakDetector;
32 private final boolean noCleaner;
33
34
35
36
37 public static final UnpooledByteBufAllocator DEFAULT =
38 new UnpooledByteBufAllocator(PlatformDependent.directBufferPreferred());
39
40
41
42
43
44
45
46 public UnpooledByteBufAllocator(boolean preferDirect) {
47 this(preferDirect, false);
48 }
49
50
51
52
53
54
55
56
57
58
59 public UnpooledByteBufAllocator(boolean preferDirect, boolean disableLeakDetector) {
60 this(preferDirect, disableLeakDetector, PlatformDependent.useDirectBufferNoCleaner());
61 }
62
63
64
65
66
67
68
69
70
71
72
73
74 public UnpooledByteBufAllocator(boolean preferDirect, boolean disableLeakDetector, boolean tryNoCleaner) {
75 super(preferDirect);
76 this.disableLeakDetector = disableLeakDetector;
77 noCleaner = tryNoCleaner && PlatformDependent.hasUnsafe()
78 && PlatformDependent.hasDirectBufferNoCleanerConstructor();
79 }
80
81 @Override
82 protected ByteBuf newHeapBuffer(int initialCapacity, int maxCapacity) {
83 return PlatformDependent.hasUnsafe() ?
84 new InstrumentedUnpooledUnsafeHeapByteBuf(this, initialCapacity, maxCapacity) :
85 new InstrumentedUnpooledHeapByteBuf(this, initialCapacity, maxCapacity);
86 }
87
88 @Override
89 protected ByteBuf newDirectBuffer(int initialCapacity, int maxCapacity) {
90 final ByteBuf buf;
91 if (PlatformDependent.hasUnsafe()) {
92 buf = noCleaner ? new InstrumentedUnpooledUnsafeNoCleanerDirectByteBuf(this, initialCapacity, maxCapacity) :
93 new InstrumentedUnpooledUnsafeDirectByteBuf(this, initialCapacity, maxCapacity);
94 } else {
95 buf = new InstrumentedUnpooledDirectByteBuf(this, initialCapacity, maxCapacity);
96 }
97 return disableLeakDetector ? buf : toLeakAwareBuffer(buf);
98 }
99
100 @Override
101 public CompositeByteBuf compositeHeapBuffer(int maxNumComponents) {
102 CompositeByteBuf buf = new CompositeByteBuf(this, false, maxNumComponents);
103 return disableLeakDetector ? buf : toLeakAwareBuffer(buf);
104 }
105
106 @Override
107 public CompositeByteBuf compositeDirectBuffer(int maxNumComponents) {
108 CompositeByteBuf buf = new CompositeByteBuf(this, true, maxNumComponents);
109 return disableLeakDetector ? buf : toLeakAwareBuffer(buf);
110 }
111
112 @Override
113 public boolean isDirectBufferPooled() {
114 return false;
115 }
116
117 @Override
118 public ByteBufAllocatorMetric metric() {
119 return metric;
120 }
121
122 void incrementDirect(int amount) {
123 metric.directCounter.add(amount);
124 }
125
126 void decrementDirect(int amount) {
127 metric.directCounter.add(-amount);
128 }
129
130 void incrementHeap(int amount) {
131 metric.heapCounter.add(amount);
132 }
133
134 void decrementHeap(int amount) {
135 metric.heapCounter.add(-amount);
136 }
137
138 private static final class InstrumentedUnpooledUnsafeHeapByteBuf extends UnpooledUnsafeHeapByteBuf {
139 InstrumentedUnpooledUnsafeHeapByteBuf(UnpooledByteBufAllocator alloc, int initialCapacity, int maxCapacity) {
140 super(alloc, initialCapacity, maxCapacity);
141 }
142
143 @Override
144 protected byte[] allocateArray(int initialCapacity) {
145 byte[] bytes = super.allocateArray(initialCapacity);
146 ((UnpooledByteBufAllocator) alloc()).incrementHeap(bytes.length);
147 return bytes;
148 }
149
150 @Override
151 protected void freeArray(byte[] array) {
152 int length = array.length;
153 super.freeArray(array);
154 ((UnpooledByteBufAllocator) alloc()).decrementHeap(length);
155 }
156 }
157
158 private static final class InstrumentedUnpooledHeapByteBuf extends UnpooledHeapByteBuf {
159 InstrumentedUnpooledHeapByteBuf(UnpooledByteBufAllocator alloc, int initialCapacity, int maxCapacity) {
160 super(alloc, initialCapacity, maxCapacity);
161 }
162
163 @Override
164 protected byte[] allocateArray(int initialCapacity) {
165 byte[] bytes = super.allocateArray(initialCapacity);
166 ((UnpooledByteBufAllocator) alloc()).incrementHeap(bytes.length);
167 return bytes;
168 }
169
170 @Override
171 protected void freeArray(byte[] array) {
172 int length = array.length;
173 super.freeArray(array);
174 ((UnpooledByteBufAllocator) alloc()).decrementHeap(length);
175 }
176 }
177
178 private static final class InstrumentedUnpooledUnsafeNoCleanerDirectByteBuf
179 extends UnpooledUnsafeNoCleanerDirectByteBuf {
180 InstrumentedUnpooledUnsafeNoCleanerDirectByteBuf(
181 UnpooledByteBufAllocator alloc, int initialCapacity, int maxCapacity) {
182 super(alloc, initialCapacity, maxCapacity);
183 }
184
185 @Override
186 protected CleanableDirectBuffer allocateDirectBuffer(int capacity) {
187 CleanableDirectBuffer buffer = super.allocateDirectBuffer(capacity);
188 return new DecrementingCleanableDirectBuffer(alloc(), buffer);
189 }
190
191 @Override
192 CleanableDirectBuffer reallocateDirect(CleanableDirectBuffer oldBuffer, int initialCapacity) {
193 int capacity = oldBuffer.buffer().capacity();
194 CleanableDirectBuffer buffer = super.reallocateDirect(oldBuffer, initialCapacity);
195 return new DecrementingCleanableDirectBuffer(alloc(), buffer, buffer.buffer().capacity() - capacity);
196 }
197 }
198
199 private static final class InstrumentedUnpooledUnsafeDirectByteBuf extends UnpooledUnsafeDirectByteBuf {
200 InstrumentedUnpooledUnsafeDirectByteBuf(
201 UnpooledByteBufAllocator alloc, int initialCapacity, int maxCapacity) {
202 super(alloc, initialCapacity, maxCapacity);
203 }
204
205 @Override
206 protected CleanableDirectBuffer allocateDirectBuffer(int capacity) {
207 CleanableDirectBuffer buffer = super.allocateDirectBuffer(capacity);
208 return new DecrementingCleanableDirectBuffer(alloc(), buffer);
209 }
210
211 @Override
212 protected ByteBuffer allocateDirect(int initialCapacity) {
213 throw new UnsupportedOperationException();
214 }
215
216 @Override
217 protected void freeDirect(ByteBuffer buffer) {
218 throw new UnsupportedOperationException();
219 }
220 }
221
222 private static final class InstrumentedUnpooledDirectByteBuf extends UnpooledDirectByteBuf {
223 InstrumentedUnpooledDirectByteBuf(
224 UnpooledByteBufAllocator alloc, int initialCapacity, int maxCapacity) {
225 super(alloc, initialCapacity, maxCapacity);
226 }
227
228 @Override
229 protected CleanableDirectBuffer allocateDirectBuffer(int initialCapacity) {
230 CleanableDirectBuffer buffer = super.allocateDirectBuffer(initialCapacity);
231 return new DecrementingCleanableDirectBuffer(alloc(), buffer);
232 }
233
234 @Override
235 protected ByteBuffer allocateDirect(int initialCapacity) {
236 throw new UnsupportedOperationException();
237 }
238
239 @Override
240 protected void freeDirect(ByteBuffer buffer) {
241 throw new UnsupportedOperationException();
242 }
243 }
244
245 private static final class DecrementingCleanableDirectBuffer implements CleanableDirectBuffer {
246 private final UnpooledByteBufAllocator alloc;
247 private final CleanableDirectBuffer delegate;
248
249 private DecrementingCleanableDirectBuffer(
250 ByteBufAllocator alloc, CleanableDirectBuffer delegate) {
251 this(alloc, delegate, delegate.buffer().capacity());
252 }
253
254 private DecrementingCleanableDirectBuffer(
255 ByteBufAllocator alloc, CleanableDirectBuffer delegate, int capacityConsumed) {
256 this.alloc = (UnpooledByteBufAllocator) alloc;
257 this.alloc.incrementDirect(capacityConsumed);
258 this.delegate = delegate;
259 }
260
261 @Override
262 public ByteBuffer buffer() {
263 return delegate.buffer();
264 }
265
266 @Override
267 public void clean() {
268 int capacity = delegate.buffer().capacity();
269 delegate.clean();
270 alloc.decrementDirect(capacity);
271 }
272
273 @Override
274 public boolean hasMemoryAddress() {
275 return delegate.hasMemoryAddress();
276 }
277
278 @Override
279 public long memoryAddress() {
280 return delegate.memoryAddress();
281 }
282 }
283
284 private static final class UnpooledByteBufAllocatorMetric implements ByteBufAllocatorMetric {
285 final LongAdder directCounter = new LongAdder();
286 final LongAdder heapCounter = new LongAdder();
287
288 @Override
289 public long usedHeapMemory() {
290 return heapCounter.sum();
291 }
292
293 @Override
294 public long usedDirectMemory() {
295 return directCounter.sum();
296 }
297
298 @Override
299 public String toString() {
300 return StringUtil.simpleClassName(this) +
301 "(usedHeapMemory: " + usedHeapMemory() + "; usedDirectMemory: " + usedDirectMemory() + ')';
302 }
303 }
304 }