0
# Object Pooling
1
2
Resource management system providing efficient object reuse patterns with configurable capacity and lifecycle management.
3
4
## Capabilities
5
6
### ObjectPool Interface
7
8
Generic object pooling interface extending Closeable for automatic resource management and efficient object reuse.
9
10
```kotlin { .api }
11
/**
12
* Generic object pool interface for efficient resource management.
13
* Provides object reuse to reduce allocation overhead and garbage collection pressure.
14
*/
15
interface ObjectPool<T> : Closeable {
16
/** Maximum number of objects the pool can hold */
17
val capacity: Int
18
19
/**
20
* Borrow an object from the pool.
21
* Creates a new instance if pool is empty and capacity allows.
22
* @return object instance ready for use
23
*/
24
fun borrow(): T
25
26
/**
27
* Return an object to the pool for future reuse.
28
* Object should be reset to clean state before recycling.
29
* @param instance object to return to pool
30
*/
31
fun recycle(instance: T)
32
33
/**
34
* Dispose all objects in the pool and release resources.
35
* Pool becomes unusable after disposal.
36
*/
37
fun dispose()
38
39
/**
40
* Close the pool (same as dispose).
41
* Implements Closeable interface for use-with-resources patterns.
42
*/
43
override fun close() = dispose()
44
}
45
```
46
47
**Usage Examples:**
48
49
```kotlin
50
import io.ktor.utils.io.pool.*
51
52
// Create a custom pool for StringBuilder objects
53
val stringBuilderPool = object : DefaultPool<StringBuilder>(capacity = 10) {
54
override fun produce(): StringBuilder = StringBuilder()
55
override fun reset(instance: StringBuilder): StringBuilder {
56
instance.clear()
57
return instance
58
}
59
}
60
61
// Use the pool
62
val sb = stringBuilderPool.borrow()
63
try {
64
sb.append("Hello ")
65
sb.append("World")
66
val result = sb.toString()
67
println(result)
68
} finally {
69
stringBuilderPool.recycle(sb)
70
}
71
72
// Pool cleanup
73
stringBuilderPool.close()
74
```
75
76
### Pool Implementation Classes
77
78
Abstract base classes and concrete implementations for different pooling strategies.
79
80
```kotlin { .api }
81
/**
82
* Abstract base class for pools with zero capacity.
83
* Always creates new instances instead of pooling.
84
*/
85
abstract class NoPoolImpl<T> : ObjectPool<T> {
86
override val capacity: Int = 0
87
88
/**
89
* Create a new instance (not pooled).
90
* @return new object instance
91
*/
92
protected abstract fun produce(): T
93
94
override fun borrow(): T = produce()
95
override fun recycle(instance: T) {} // No-op for zero capacity
96
override fun dispose() {} // No-op for zero capacity
97
}
98
99
/**
100
* Abstract pool that produces at most one instance.
101
* Suitable for expensive-to-create singleton-like objects.
102
*/
103
abstract class SingleInstancePool<T> : ObjectPool<T> {
104
override val capacity: Int = 1
105
106
/**
107
* Create the single instance.
108
* @return new object instance
109
*/
110
protected abstract fun produce(): T
111
112
/**
113
* Reset instance to clean state before reuse.
114
* @param instance object to reset
115
* @return reset object (same instance or replacement)
116
*/
117
protected abstract fun reset(instance: T): T
118
119
override fun borrow(): T
120
override fun recycle(instance: T)
121
override fun dispose()
122
}
123
124
/**
125
* Default pool implementation with configurable capacity.
126
* Thread-safe implementation optimized for concurrent access.
127
*/
128
abstract class DefaultPool<T>(override val capacity: Int) : ObjectPool<T> {
129
/**
130
* Create a new instance when pool is empty.
131
* @return new object instance
132
*/
133
protected abstract fun produce(): T
134
135
/**
136
* Reset instance to clean state before recycling.
137
* @param instance object to reset
138
* @return reset object (same instance or replacement)
139
*/
140
protected open fun reset(instance: T): T = instance
141
142
/**
143
* Validate instance before recycling.
144
* @param instance object to validate
145
* @return true if instance can be recycled
146
*/
147
protected open fun validateInstance(instance: T): Boolean = true
148
149
/**
150
* Dispose an instance when it cannot be recycled.
151
* @param instance object to dispose
152
*/
153
protected open fun disposeInstance(instance: T) {}
154
155
override fun borrow(): T
156
override fun recycle(instance: T)
157
override fun dispose()
158
}
159
```
160
161
**Usage Examples:**
162
163
```kotlin
164
import io.ktor.utils.io.pool.*
165
166
// Custom pool with validation
167
class ByteArrayPool(capacity: Int, private val arraySize: Int) : DefaultPool<ByteArray>(capacity) {
168
override fun produce(): ByteArray = ByteArray(arraySize)
169
170
override fun reset(instance: ByteArray): ByteArray {
171
instance.fill(0) // Clear array
172
return instance
173
}
174
175
override fun validateInstance(instance: ByteArray): Boolean {
176
return instance.size == arraySize // Ensure correct size
177
}
178
}
179
180
val pool = ByteArrayPool(capacity = 5, arraySize = 1024)
181
182
// Use pool with validation
183
val array = pool.borrow()
184
// ... use array ...
185
pool.recycle(array) // Will be validated and reset
186
187
// Single instance pool example
188
class ExpensiveResourcePool : SingleInstancePool<ExpensiveResource>() {
189
override fun produce(): ExpensiveResource = ExpensiveResource()
190
191
override fun reset(instance: ExpensiveResource): ExpensiveResource {
192
instance.reset()
193
return instance
194
}
195
}
196
```
197
198
### ByteArrayPool Object
199
200
Pre-configured global pool for byte arrays with optimized settings for I/O operations.
201
202
```kotlin { .api }
203
/**
204
* Global byte array pool optimized for I/O operations.
205
* Provides efficient reuse of byte arrays to reduce allocation overhead.
206
*/
207
object ByteArrayPool : ObjectPool<ByteArray> {
208
override val capacity: Int
209
210
/**
211
* Borrow a byte array from the global pool.
212
* Array size is implementation-specific and optimized for common I/O operations.
213
* @return byte array ready for use
214
*/
215
override fun borrow(): ByteArray
216
217
/**
218
* Return byte array to the global pool.
219
* Array will be reused for future borrow() calls.
220
* @param instance byte array to recycle
221
*/
222
override fun recycle(instance: ByteArray)
223
224
override fun dispose()
225
override fun close() = dispose()
226
}
227
```
228
229
**Usage Examples:**
230
231
```kotlin
232
import io.ktor.utils.io.pool.*
233
import io.ktor.utils.io.*
234
235
// Use global byte array pool
236
val buffer = ByteArrayPool.borrow()
237
try {
238
// Perform I/O operations with the buffer
239
val channel: ByteReadChannel = TODO()
240
val bytesRead = channel.readAvailable(buffer, 0, buffer.size)
241
242
// Process data in buffer
243
processData(buffer, bytesRead)
244
} finally {
245
// Always return to pool
246
ByteArrayPool.recycle(buffer)
247
}
248
249
// Integration with channels
250
suspend fun efficientCopy(source: ByteReadChannel, dest: ByteWriteChannel) {
251
val buffer = ByteArrayPool.borrow()
252
try {
253
while (!source.isClosedForRead) {
254
val bytesRead = source.readAvailable(buffer, 0, buffer.size)
255
if (bytesRead > 0) {
256
dest.writeFully(buffer, 0, bytesRead)
257
}
258
}
259
} finally {
260
ByteArrayPool.recycle(buffer)
261
}
262
}
263
```
264
265
### Pool Utility Functions
266
267
Utility functions for convenient pool usage with automatic resource management.
268
269
```kotlin { .api }
270
/**
271
* Use an object from the pool with automatic return.
272
* Ensures object is returned to pool even if block throws exception.
273
* @param block operation to perform with borrowed object
274
* @return result of the block operation
275
*/
276
inline fun <T : Any, R> ObjectPool<T>.useInstance(block: (T) -> R): R
277
```
278
279
**Usage Examples:**
280
281
```kotlin
282
import io.ktor.utils.io.pool.*
283
284
// Safe pool usage with automatic cleanup
285
val result = ByteArrayPool.useInstance { buffer ->
286
// Use buffer safely - it will be automatically returned
287
performIOOperation(buffer)
288
"Operation completed"
289
}
290
291
// Custom pool with useInstance
292
class StringBuilderPool : DefaultPool<StringBuilder>(capacity = 10) {
293
override fun produce(): StringBuilder = StringBuilder()
294
override fun reset(instance: StringBuilder): StringBuilder {
295
instance.clear()
296
return instance
297
}
298
}
299
300
val pool = StringBuilderPool()
301
302
val formattedString = pool.useInstance { sb ->
303
sb.append("User: ")
304
sb.append("Alice")
305
sb.append(", Age: ")
306
sb.append(25)
307
sb.toString()
308
}
309
310
// Multiple nested pool usage
311
val complexResult = pool.useInstance { outerSb ->
312
outerSb.append("Outer: ")
313
314
val innerResult = pool.useInstance { innerSb ->
315
innerSb.append("Inner content")
316
innerSb.toString()
317
}
318
319
outerSb.append(innerResult)
320
outerSb.toString()
321
}
322
```
323
324
### Pool Configuration and Best Practices
325
326
Configuration options and usage patterns for optimal pool performance.
327
328
```kotlin { .api }
329
/**
330
* No-pool implementation that always creates new instances.
331
* Use when pooling overhead exceeds benefits.
332
*/
333
fun <T> ObjectPool.Companion.NoPool(): ObjectPool<T> where T : Any
334
335
/**
336
* Create a simple pool with basic configuration.
337
* @param capacity maximum objects to pool
338
* @param produce factory function for creating instances
339
* @param reset optional reset function for cleaning instances
340
* @return configured pool instance
341
*/
342
fun <T> ObjectPool.Companion.create(
343
capacity: Int,
344
produce: () -> T,
345
reset: (T) -> T = { it }
346
): ObjectPool<T>
347
```
348
349
**Best Practices Examples:**
350
351
```kotlin
352
import io.ktor.utils.io.pool.*
353
354
// Choose appropriate pool size based on usage patterns
355
class OptimizedBufferPool {
356
// Small pool for frequent, short-lived operations
357
private val smallBuffers = object : DefaultPool<ByteArray>(capacity = 16) {
358
override fun produce() = ByteArray(1024)
359
}
360
361
// Larger pool for less frequent, longer-lived operations
362
private val largeBuffers = object : DefaultPool<ByteArray>(capacity = 4) {
363
override fun produce() = ByteArray(64 * 1024)
364
}
365
366
fun borrowSmall(): ByteArray = smallBuffers.borrow()
367
fun recycleSmall(buffer: ByteArray) = smallBuffers.recycle(buffer)
368
369
fun borrowLarge(): ByteArray = largeBuffers.borrow()
370
fun recycleLarge(buffer: ByteArray) = largeBuffers.recycle(buffer)
371
}
372
373
// Pool with validation and cleanup
374
class ValidatingPool<T>(
375
capacity: Int,
376
private val factory: () -> T,
377
private val validator: (T) -> Boolean,
378
private val cleaner: (T) -> T
379
) : DefaultPool<T>(capacity) {
380
381
override fun produce(): T = factory()
382
383
override fun validateInstance(instance: T): Boolean = validator(instance)
384
385
override fun reset(instance: T): T = cleaner(instance)
386
}
387
388
// Thread-safe usage pattern
389
class ThreadSafePoolUser {
390
private val pool = object : DefaultPool<StringBuilder>(10) {
391
override fun produce() = StringBuilder()
392
override fun reset(instance: StringBuilder) = instance.apply { clear() }
393
}
394
395
fun formatMessage(user: String, message: String): String {
396
return pool.useInstance { sb ->
397
sb.append("[")
398
sb.append(System.currentTimeMillis())
399
sb.append("] ")
400
sb.append(user)
401
sb.append(": ")
402
sb.append(message)
403
sb.toString()
404
}
405
}
406
}
407
408
// Resource lifecycle management
409
class ManagedPoolExample : AutoCloseable {
410
private val pools = mutableListOf<ObjectPool<*>>()
411
412
fun <T> createPool(
413
capacity: Int,
414
factory: () -> T,
415
cleaner: (T) -> T = { it }
416
): ObjectPool<T> {
417
val pool = object : DefaultPool<T>(capacity) {
418
override fun produce() = factory()
419
override fun reset(instance: T) = cleaner(instance)
420
}
421
pools.add(pool)
422
return pool
423
}
424
425
override fun close() {
426
pools.forEach { it.dispose() }
427
pools.clear()
428
}
429
}
430
```