ByteBufferPoolManager.java
/*
* SPDX-FileCopyrightText: 2025 Lucimber UG
* SPDX-License-Identifier: Apache-2.0
*/
package com.lucimber.dbus.util;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.util.concurrent.atomic.AtomicLong;
import java.util.concurrent.atomic.LongAdder;
/**
* A singleton manager for ByteBuffer pooling with performance metrics.
*
* <p>This manager provides a global instance of ByteBufferPool and tracks performance metrics to
* help identify optimization opportunities.
*/
public final class ByteBufferPoolManager {
private static final ByteBufferPoolManager INSTANCE = new ByteBufferPoolManager();
private final ByteBufferPool pool;
private final LongAdder acquireCount;
private final LongAdder releaseCount;
private final LongAdder poolHitCount;
private final LongAdder poolMissCount;
private final AtomicLong totalBytesAllocated;
private ByteBufferPoolManager() {
this.pool = new ByteBufferPool();
this.acquireCount = new LongAdder();
this.releaseCount = new LongAdder();
this.poolHitCount = new LongAdder();
this.poolMissCount = new LongAdder();
this.totalBytesAllocated = new AtomicLong();
}
/**
* Gets the singleton instance of ByteBufferPoolManager.
*
* @return the singleton instance
*/
public static ByteBufferPoolManager getInstance() {
return INSTANCE;
}
/**
* Acquires a ByteBuffer with at least the requested capacity.
*
* @param capacity minimum required capacity
* @param order byte order for the buffer
* @return a ByteBuffer ready for use
*/
public ByteBuffer acquire(int capacity, ByteOrder order) {
acquireCount.increment();
// Track whether we get a pooled buffer or allocate a new one
long beforeAllocated = totalBytesAllocated.get();
ByteBuffer buffer = pool.acquire(capacity, order);
long afterAllocated = totalBytesAllocated.get();
if (afterAllocated > beforeAllocated) {
poolMissCount.increment();
totalBytesAllocated.addAndGet(buffer.capacity());
} else {
poolHitCount.increment();
}
return buffer;
}
/**
* Returns a ByteBuffer to the pool for potential reuse.
*
* @param buffer the buffer to return (may be null)
*/
public void release(ByteBuffer buffer) {
if (buffer != null) {
releaseCount.increment();
pool.release(buffer);
}
}
/**
* Gets performance metrics for the buffer pool.
*
* @return a formatted string with performance statistics
*/
public String getPerformanceMetrics() {
long acquires = acquireCount.sum();
long releases = releaseCount.sum();
long hits = poolHitCount.sum();
long misses = poolMissCount.sum();
double hitRate = acquires > 0 ? (double) hits / acquires * 100 : 0;
StringBuilder sb = new StringBuilder("ByteBufferPool Performance Metrics:\n");
sb.append(String.format(" Acquires: %d\n", acquires));
sb.append(String.format(" Releases: %d\n", releases));
sb.append(String.format(" Pool Hits: %d (%.1f%%)\n", hits, hitRate));
sb.append(String.format(" Pool Misses: %d\n", misses));
sb.append(String.format(" Total Allocated: %d KB\n", totalBytesAllocated.get() / 1024));
sb.append(String.format(" Buffers in Flight: %d\n", acquires - releases));
sb.append("\n");
sb.append(pool.getStatistics());
return sb.toString();
}
/** Resets all performance metrics. Useful for testing or monitoring specific periods. */
public void resetMetrics() {
acquireCount.reset();
releaseCount.reset();
poolHitCount.reset();
poolMissCount.reset();
totalBytesAllocated.set(0);
}
/** Clears the pool and resets metrics. */
public void clear() {
pool.clear();
resetMetrics();
}
}