Skip to content

CoralPool is a high-performance, lightweight and garbage-free Java object pool implementation. It efficiently reuses mutable objects, minimizing the creation of short-lived objects that would otherwise burden the garbage collector.

License

Notifications You must be signed in to change notification settings

coralblocks/CoralPool

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

CoralPool

CoralPool is a high-performance, lightweight and garbage-free Java object pool implementation. It efficiently reuses mutable objects, minimizing the creation of short-lived objects that would otherwise burden the garbage collector. The pool can grow to accommodate more instances by internally allocating new objects via the get() method or by accepting external objects (not originally allocated by the pool) through the release(E) method.

Note: For a discussion of developing garbage-free applications you should refer to this video

ObjectPool Interface

public interface ObjectPool<E> {

   /**
    * Retrieves an instance from this object pool. If no instances are currently available,
    * a new instance will be created, and the pool will grow in size if necessary to 
    * accommodate more instances. This method can never return null.
    * 
    * @return an instance from the pool
    */
    public E get();

   /**
    * Returns an instance to this object pool. If the pool has no available space 
    * to accommodate the instance, it will expand as needed. The pool can accept 
    * external instances that were not necessarily created by it. 
    * Passing null as the instance will result in an exception being thrown.
    * 
    * @param instance the instance to return to the pool
    * @throws IllegalArgumentException if the provided instance is null
    */
    public void release(E instance);
}

Example:

// the pool can grow, but it will start with 100 slots
final int initialCapacity = 100;

// the pool can allocate more instances later, but it will start with 50 instances
final int preloadCount = 50;

// the pool can use an ObjectBuilder, but it can also take a Class for creating instances through
// the default constructor
final Class<StringBuilder> klass = StringBuilder.class;

// Create your object pool
ObjectPool<StringBuilder> pool = new LinkedObjectPool<>(initialCapacity, preloadCount, klass);

// Fetch an instance from the pool
StringBuilder sb = pool.get();

// Do whatever you want with the instance
// (...)

// When you are done return the instance back to the pool
pool.release(sb);

ObjectPool Implementations

LinkedObjectPool

An ObjectPool backed by an internal linked-list. It can gradually grow by adding new nodes to the list.

ArrayObjectPool

An ObjectPool backed by an internal array. It can expand by allocating a larger array. When that happens, the previous array is retained as a SoftReference to delay garbage collection as much as possible. You can manually release these references by calling its releaseSoftReferences() public method.

MultiArrayObjectPool

An ObjectPool backed by an internal doubly linked-list of arrays. It expands by adding new nodes, each containing a newly allocated array, to the linked-list.

StackObjectPool

An ObjectPool backed by an internal stack, implemented with an array. It can expand by allocating a larger stack. When that happens, the previous array of the stack is retained as a SoftReference to delay garbage collection as much as possible. You can manually release these references by calling its releaseSoftReferences() public method.

TieredObjectPool

An ObjectPool implementation utilizing a two-tier structure: an internal array and a linked-list. It grows by adding new instances to the linked-list (second tier), ensuring the array (first tier) remains a fixed size and does not require expansion.

Benchmarks

Ideally, an object pool should be configured at startup with a big enough initial capacity to avoid growth, maximizing performance. However, since growth cannot always be avoided, we conducted two benchmarks: one where the pool remains fixed in size and another where it grows. In the growth benchmark, the pool expands exclusively through additional get() calls, not by adding external instances via the release(E) method. Adding external instances, those not created internally by the pool, is rarely needed or desirable.

You can find the benchmarks here (without growth) and here (with growth). Below the results:

Note: We used the new JVMCI JIT (from Graal 23) for the benchmarks below

Benchmark (without growth)

LinkedObjectPool        => 9,698,254 nanoseconds
ArrayObjectPool         => 3,658,073 nanoseconds     
MultiArrayObjectPool    => 3,900,745 nanoseconds
StackObjectPool         => 3,813,075 nanoseconds
TieredObjectPool        => 3,786,247 nanoseconds                   

The results above are expected as native arrays are faster than linked lists because they store elements in contiguous memory, enhancing cache locality and sequential access. In contrast, linked lists use scattered references across memory, leading to more cache misses and slower traversal time due to the overhead of following pointers.

Benchmark (with growth)

LinkedObjectPool        => 241,073 microseconds
ArrayObjectPool         => 87,784 microseconds     
MultiArrayObjectPool    => 162,697 microseconds
StackObjectPool         => 129,899 microseconds
TieredObjectPool        => 237,377 microseconds                   

The above results are expected because TieredObjectPool uses a linked list for growth, leading to the same cache miss inefficiencies observed in the previous benchmark without growth. In contrast, ArrayObjectPool clearly outperforms all others, as its growth implementation is more efficient by avoiding both array copying and nulling.

Note: All benchmarks were executed with -verbose:gc to make sure no GC activity ever takes place

About

CoralPool is a high-performance, lightweight and garbage-free Java object pool implementation. It efficiently reuses mutable objects, minimizing the creation of short-lived objects that would otherwise burden the garbage collector.

Topics

Resources

License

Stars

Watchers

Forks

Packages