public @NotNull ByteBuffer allocate(int size) {
    if (useBuffersCache()) {
      Map.Entry<Integer, ArrayBlockingQueue<ByteBuffer>> buffersOfCapacity = buffersPool.ceilingEntry(size);

      while (buffersOfCapacity != null) {

        int capacity = buffersOfCapacity.getKey();
        if (capacity > size * 2) {
          //It's ok to use buffer(capacity: 32k) to serve request of size=16k, but we don't want to
          // use 10M buffer to serve request of size=16k because it is too much waste.
          // By limiting the capacity <=2*size we limit the amount of memory wasted due to 'rounding'.
          // If we can't serve the request from pool wasting no more than twice the requested memory
          // -- fallback to allocating the buffer from JVM (and hope JVM/stdlib/OS allocators are
          // smart enough to not waste even more memory than we could have been wasted :).

          break;
        }

        ByteBuffer cachedBuffer = buffersOfCapacity.getValue().poll();
        if (cachedBuffer != null) {
          cachedBuffer.clear().limit(size);
          totalSizeOfBuffersInCache.addAndGet(-capacity);
          hits.incrementAndGet();
          return cachedBuffer;
        }

        //Don't remove the entry even though it is empty -- because it creates race condition
        // with adding the same entry again, and some buffers may be lost due to that race.

        buffersOfCapacity = buffersPool.higherEntry(capacity);
      }
    }

    misses.incrementAndGet();
    totalSizeOfBuffersAllocated.addAndGet(size);
    return allocateNewBuffer(size);
  }
public @NotNull ByteBuffer allocate(int size)