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 protected CleanableDirectBuffer allocateDirectBuffer(int capacity, boolean permitExpensiveClean) {
193 CleanableDirectBuffer buffer = super.allocateDirectBuffer(capacity, permitExpensiveClean);
194 return new DecrementingCleanableDirectBuffer(alloc(), buffer);
195 }
196
197 @Override
198 CleanableDirectBuffer reallocateDirect(CleanableDirectBuffer oldBuffer, int newCapacity) {
199 int oldCapacity = oldBuffer.buffer().capacity();
200 CleanableDirectBuffer buffer = super.reallocateDirect(oldBuffer, newCapacity);
201 return new DecrementingCleanableDirectBuffer(
202 alloc(), buffer, buffer.buffer().capacity() - oldCapacity);
203 }
204 }
205
206 private static final class InstrumentedUnpooledUnsafeDirectByteBuf extends UnpooledUnsafeDirectByteBuf {
207 InstrumentedUnpooledUnsafeDirectByteBuf(
208 UnpooledByteBufAllocator alloc, int initialCapacity, int maxCapacity) {
209 super(alloc, initialCapacity, maxCapacity);
210 }
211
212 @Override
213 protected CleanableDirectBuffer allocateDirectBuffer(int capacity) {
214 CleanableDirectBuffer buffer = super.allocateDirectBuffer(capacity);
215 return new DecrementingCleanableDirectBuffer(alloc(), buffer);
216 }
217
218 @Override
219 protected CleanableDirectBuffer allocateDirectBuffer(int capacity, boolean permitExpensiveClean) {
220 CleanableDirectBuffer buffer = super.allocateDirectBuffer(capacity, permitExpensiveClean);
221 return new DecrementingCleanableDirectBuffer(alloc(), buffer);
222 }
223
224 @Override
225 protected ByteBuffer allocateDirect(int initialCapacity) {
226 throw new UnsupportedOperationException();
227 }
228
229 @Override
230 protected void freeDirect(ByteBuffer buffer) {
231 throw new UnsupportedOperationException();
232 }
233 }
234
235 private static final class InstrumentedUnpooledDirectByteBuf extends UnpooledDirectByteBuf {
236 InstrumentedUnpooledDirectByteBuf(
237 UnpooledByteBufAllocator alloc, int initialCapacity, int maxCapacity) {
238 super(alloc, initialCapacity, maxCapacity);
239 }
240
241 @Override
242 protected CleanableDirectBuffer allocateDirectBuffer(int initialCapacity) {
243 CleanableDirectBuffer buffer = super.allocateDirectBuffer(initialCapacity);
244 return new DecrementingCleanableDirectBuffer(alloc(), buffer);
245 }
246
247 @Override
248 protected CleanableDirectBuffer allocateDirectBuffer(int initialCapacity, boolean permitExpensiveClean) {
249 CleanableDirectBuffer buffer = super.allocateDirectBuffer(initialCapacity, permitExpensiveClean);
250 return new DecrementingCleanableDirectBuffer(alloc(), buffer);
251 }
252
253 @Override
254 protected ByteBuffer allocateDirect(int initialCapacity) {
255 throw new UnsupportedOperationException();
256 }
257
258 @Override
259 protected void freeDirect(ByteBuffer buffer) {
260 throw new UnsupportedOperationException();
261 }
262 }
263
264 private static final class DecrementingCleanableDirectBuffer implements CleanableDirectBuffer {
265 private final UnpooledByteBufAllocator alloc;
266 private final CleanableDirectBuffer delegate;
267
268 private DecrementingCleanableDirectBuffer(
269 ByteBufAllocator alloc, CleanableDirectBuffer delegate) {
270 this(alloc, delegate, delegate.buffer().capacity());
271 }
272
273 private DecrementingCleanableDirectBuffer(
274 ByteBufAllocator alloc, CleanableDirectBuffer delegate, int capacityConsumed) {
275 this.alloc = (UnpooledByteBufAllocator) alloc;
276 this.alloc.incrementDirect(capacityConsumed);
277 this.delegate = delegate;
278 }
279
280 @Override
281 public ByteBuffer buffer() {
282 return delegate.buffer();
283 }
284
285 @Override
286 public void clean() {
287 int capacity = delegate.buffer().capacity();
288 delegate.clean();
289 alloc.decrementDirect(capacity);
290 }
291
292 @Override
293 public boolean hasMemoryAddress() {
294 return delegate.hasMemoryAddress();
295 }
296
297 @Override
298 public long memoryAddress() {
299 return delegate.memoryAddress();
300 }
301 }
302
303 private static final class UnpooledByteBufAllocatorMetric implements ByteBufAllocatorMetric {
304 final LongAdder directCounter = new LongAdder();
305 final LongAdder heapCounter = new LongAdder();
306
307 @Override
308 public long usedHeapMemory() {
309 return heapCounter.sum();
310 }
311
312 @Override
313 public long usedDirectMemory() {
314 return directCounter.sum();
315 }
316
317 @Override
318 public String toString() {
319 return StringUtil.simpleClassName(this) +
320 "(usedHeapMemory: " + usedHeapMemory() + "; usedDirectMemory: " + usedDirectMemory() + ')';
321 }
322 }
323 }