/// <summary>
/// Determines whether to allocate more memory or to do a collection cycle on the existing pool.
/// </summary>
private void RequestMoreFreeBlocks()
{
Stopwatch sw = new Stopwatch();
sw.Start();
StringBuilder sb = new StringBuilder();
sb.AppendLine("Collection Cycle Started");
bool lockTaken;
Monitor.Enter(m_syncRoot); lockTaken = true;
try
{
long size = CurrentCapacity;
int collectionLevel = GetCollectionLevelBasedOnSize(size);
long stopShrinkingLimit = CalculateStopShrinkingLimit(size);
RemoveDeadEvents();
sb.Append("Level: " + GetCollectionLevelString(collectionLevel));
sb.AppendFormat(" Desired Size: {0}/{1}MB", stopShrinkingLimit >> 20, CurrentCapacity >> 20);
sb.AppendLine();
for (int x = 0; x < collectionLevel; x++)
{
if (CurrentAllocatedSize < stopShrinkingLimit)
{
break;
}
CollectionEventArgs eventArgs = new CollectionEventArgs(ReleasePage, MemoryPoolCollectionMode.Normal, 0);
Monitor.Exit(m_syncRoot); lockTaken = false;
foreach (WeakEventHandler <CollectionEventArgs> c in m_requestCollectionEvent)
{
c.TryInvoke(this, eventArgs);
}
Monitor.Enter(m_syncRoot); lockTaken = true;
sb.AppendFormat("Pass {0} Usage: {1}/{2}MB", x + 1, CurrentAllocatedSize >> 20, CurrentCapacity >> 20);
sb.AppendLine();
}
long currentSize = CurrentAllocatedSize;
long sizeBefore = CurrentCapacity;
if (m_pageList.GrowMemoryPool(currentSize + (long)(0.1 * MaximumPoolSize)))
{
long sizeAfter = CurrentCapacity;
m_releasePageVersion++;
sb.AppendFormat("Grew buffer pool {0}MB -> {1}MB", sizeBefore >> 20, sizeAfter >> 20);
sb.AppendLine();
}
if (m_pageList.FreeSpaceBytes < 0.05 * MaximumPoolSize)
{
int pagesToBeReleased = (int)((0.05 * MaximumPoolSize - m_pageList.FreeSpaceBytes) / PageSize);
sb.AppendFormat("* Emergency Collection Occuring. Attempting to release {0} pages.", pagesToBeReleased);
sb.AppendLine();
Log.Publish(MessageLevel.Warning, MessageFlags.PerformanceIssue, "Pool Emergency", string.Format("Memory pool is reaching an Emergency level. Desiring Pages To Release: {0}", pagesToBeReleased));
CollectionEventArgs eventArgs = new CollectionEventArgs(ReleasePage, MemoryPoolCollectionMode.Emergency, pagesToBeReleased);
Monitor.Exit(m_syncRoot); lockTaken = false;
foreach (WeakEventHandler <CollectionEventArgs> c in m_requestCollectionEvent)
{
if (eventArgs.DesiredPageReleaseCount == 0)
{
break;
}
c.TryInvoke(this, eventArgs);
}
Monitor.Enter(m_syncRoot); lockTaken = true;
if (eventArgs.DesiredPageReleaseCount > 0)
{
sb.AppendFormat("** Critical Collection Occuring. Attempting to release {0} pages.", pagesToBeReleased);
sb.AppendLine();
Log.Publish(MessageLevel.Warning, MessageFlags.PerformanceIssue, "Pool Critical", string.Format("Memory pool is reaching an Critical level. Desiring Pages To Release: {0}", eventArgs.DesiredPageReleaseCount));
eventArgs = new CollectionEventArgs(ReleasePage, MemoryPoolCollectionMode.Critical, eventArgs.DesiredPageReleaseCount);
Monitor.Exit(m_syncRoot); lockTaken = false;
foreach (WeakEventHandler <CollectionEventArgs> c in m_requestCollectionEvent)
{
if (eventArgs.DesiredPageReleaseCount == 0)
{
break;
}
c.TryInvoke(this, eventArgs);
}
Monitor.Enter(m_syncRoot); lockTaken = true;
}
}
sw.Stop();
sb.AppendFormat("Elapsed Time: {0}ms", sw.Elapsed.TotalMilliseconds.ToString("0.0"));
Log.Publish(MessageLevel.Info, "Memory Pool Collection Occured", sb.ToString());
RemoveDeadEvents();
}
finally
{
if (lockTaken)
{
Monitor.Exit(m_syncRoot);
}
}
}