/// <summary> /// Internal function called by the plugin to remove old, non-used buffers. /// </summary> internal static void Maintain() { DateTime now = DateTime.UtcNow; if (!_isEnabled || lastMaintenance + RunMaintenanceEvery > now) { return; } lastMaintenance = now; //if (HTTPManager.Logger.Level == Logger.Loglevels.All) // HTTPManager.Logger.Information("VariableSizedBufferPool", "Before Maintain: " + GetStatistics()); DateTime olderThan = now - RemoveOlderThan; rwLock.EnterWriteLock(); try { for (int i = 0; i < FreeBuffers.Count; ++i) { BufferStore store = FreeBuffers[i]; List <BufferDesc> buffers = store.buffers; for (int cv = buffers.Count - 1; cv >= 0; cv--) { BufferDesc desc = buffers[cv]; if (desc.released < olderThan) { // buffers stores available buffers ascending by age. So, when we find an old enough, we can // delete all entries in the [0..cv] range. int removeCount = cv + 1; buffers.RemoveRange(0, removeCount); PoolSize -= (int)(removeCount * store.Size); break; } } if (RemoveEmptyLists && buffers.Count == 0) { FreeBuffers.RemoveAt(i--); } } } finally { rwLock.ExitWriteLock(); } //if (HTTPManager.Logger.Level == Logger.Loglevels.All) // HTTPManager.Logger.Information("VariableSizedBufferPool", "After Maintain: " + GetStatistics()); }
/// <summary> /// Get byte[] from the pool. If canBeLarge is true, the returned buffer might be larger than the requested size. /// </summary> public static byte[] Get(long size, bool canBeLarger) { if (!_isEnabled) { return(new byte[size]); } // Return a fix reference for 0 length requests. Any resize call (even Array.Resize) creates a new reference // so we are safe to expose it to multiple callers. if (size == 0) { return(BufferPool.NoData); } if (FreeBuffers.Count == 0) { return(new byte[size]); } BufferDesc bufferDesc = FindFreeBuffer(size, canBeLarger); if (bufferDesc.buffer == null) { if (canBeLarger) { if (size < MinBufferSize) { size = MinBufferSize; } else if (!IsPowerOfTwo(size)) { size = NextPowerOf2(size); } } return(new byte[size]); } else { Interlocked.Increment(ref GetBuffers); } Interlocked.Add(ref PoolSize, -bufferDesc.buffer.Length); return(bufferDesc.buffer); }
private static BufferDesc FindFreeBuffer(long size, bool canBeLarger) { rwLock.EnterUpgradeableReadLock(); try { for (int i = 0; i < FreeBuffers.Count; ++i) { BufferStore store = FreeBuffers[i]; if (store.buffers.Count > 0 && (store.Size == size || (canBeLarger && store.Size > size))) { // Getting the last one has two desired effect: // 1.) RemoveAt should be quicker as it don't have to move all the remaining entries // 2.) Old, non-used buffers will age. Getting a buffer and putting it back will not keep buffers fresh. BufferDesc lastFree = store.buffers[store.buffers.Count - 1]; rwLock.EnterWriteLock(); try { store.buffers.RemoveAt(store.buffers.Count - 1); } finally { rwLock.ExitWriteLock(); } return(lastFree); } } } finally { rwLock.ExitUpgradeableReadLock(); } return(BufferDesc.Empty); }
/// <summary> /// Get byte[] from the pool. If canBeLarge is true, the returned buffer might be larger than the requested size. /// </summary> public static byte[] Get(long size, bool canBeLarger) { if (!_isEnabled) { return(new byte[size]); } // Return a fix reference for 0 length requests. Any resize call (even Array.Resize) creates a new reference // so we are safe to expose it to multiple callers. if (size == 0) { return(BufferPool.NoData); } #if UNITY_EDITOR if (EnableDebugStackTraceCollection) { lock (getStackStats) { string stack = ProcessStackTrace(System.Environment.StackTrace); int value; if (!getStackStats.TryGetValue(stack, out value)) { getStackStats.Add(stack, 1); } else { getStackStats[stack] = ++value; } } } #endif if (canBeLarger) { if (size < MinBufferSize) { size = MinBufferSize; } else if (!IsPowerOfTwo(size)) { size = NextPowerOf2(size); } } if (FreeBuffers.Count == 0) { return(new byte[size]); } BufferDesc bufferDesc = FindFreeBuffer(size, canBeLarger); if (bufferDesc.buffer == null) { return(new byte[size]); } else { Interlocked.Increment(ref GetBuffers); } Interlocked.Add(ref PoolSize, -bufferDesc.buffer.Length); return(bufferDesc.buffer); }