ByteBuffer (int bufferSize) { checkNotClosed(); for (int attempt = 0; ; attempt++) { ByteBuffer allocatedBuffer = memoryManager.tryAllocate(bufferSize, /* aboveCapacity: */ false); if (allocatedBuffer != null) { return allocatedBuffer; } ByteBuffer reclaimedBuffer = tryReclaimPageOfSize(bufferSize, MAX_PAGES_TO_TRY_RECLAIM_ON_ALLOCATION); if (reclaimedBuffer != null) { statistics.pageReclaimedByHandover(bufferSize, reclaimedBuffer.isDirect()); return reclaimedBuffer; } ByteBuffer aboveCapacityBuffer = memoryManager.tryAllocate(bufferSize, /* aboveCapacity: */ true); if (aboveCapacityBuffer != null) { return aboveCapacityBuffer; } //Wakeup housekeeper, and wait for it to collect more pages statistics.pageAllocationWaited(); wakeupHousekeeper(); pagesToProbablyReclaim.waitForRefill(1 /*ms*/); //MAYBE RC: Waiting for housekeeper to collect new portion of pages for us -- is basically a // backpressure. We slow down the current thread so the housekeeper could keep up. // We could avoid this waiting by assisting housekeeper instead -- i.e. we could scan through // PageTables looking for the first page ready to reclaim. // // So far I think that would be an overkill: if some thread(s) requests pages so greedy that // housekeeper can't keep up -- it is better to slow that thread down with backpressure than // to allow the greedy thread to churn pages wildly. // Backpressure is ~1ms (housekeeper turn period), so it unlikely creates freezes noticeable // to user, but it makes Cache more fair/cooperative, by prohibiting single thread to exhaust // cache throughput. // Time will tell is it correct reasoning. } }