|
|
@@ -697,6 +697,10 @@ PageAllocatorBase<TVirtualAlloc, TSegment, TPageSegment>::PageAllocatorBase(Allo
|
|
|
#endif
|
|
|
minFreePageCount(0),
|
|
|
isUsed(false),
|
|
|
+ waitingToEnterIdleDecommit(false),
|
|
|
+#if DBG
|
|
|
+ idleDecommitBackOffCount(0),
|
|
|
+#endif
|
|
|
idleDecommitEnterCount(1),
|
|
|
isClosed(false),
|
|
|
stopAllocationOnOutOfMemory(stopAllocationOnOutOfMemory),
|
|
|
@@ -1971,14 +1975,22 @@ PageAllocatorBase<TVirtualAlloc, TSegment, TPageSegment>::DecommitNow(bool all)
|
|
|
int numZeroPagesFreed = 0;
|
|
|
|
|
|
// There might be queued zero pages. Drain them first
|
|
|
-
|
|
|
+ bool zeroPageQueueEmpty = false;
|
|
|
while (true)
|
|
|
{
|
|
|
FreePageEntry * freePageEntry = PopPendingZeroPage();
|
|
|
if (freePageEntry == nullptr)
|
|
|
{
|
|
|
+ zeroPageQueueEmpty = true;
|
|
|
break;
|
|
|
}
|
|
|
+
|
|
|
+ // Back-off from decommit if we are trying to enter IdleDecommit again.
|
|
|
+ if (this->waitingToEnterIdleDecommit)
|
|
|
+ {
|
|
|
+ break;
|
|
|
+ }
|
|
|
+
|
|
|
PAGE_ALLOC_TRACE_AND_STATS_0(_u("Freeing page from zero queue"));
|
|
|
TPageSegment * segment = freePageEntry->segment;
|
|
|
uint pageCount = freePageEntry->pageCount;
|
|
|
@@ -2021,6 +2033,7 @@ PageAllocatorBase<TVirtualAlloc, TSegment, TPageSegment>::DecommitNow(bool all)
|
|
|
|
|
|
// Take the lock to make sure the recycler thread has finished zeroing out the pages after
|
|
|
// we drained the queue
|
|
|
+ if(zeroPageQueueEmpty)
|
|
|
{
|
|
|
AutoCriticalSection autoCS(&backgroundPageQueue->backgroundPageQueueCriticalSection);
|
|
|
this->hasZeroQueuedPages = false;
|
|
|
@@ -2099,12 +2112,18 @@ PageAllocatorBase<TVirtualAlloc, TSegment, TPageSegment>::DecommitNow(bool all)
|
|
|
|
|
|
}
|
|
|
pageToDecommit -= pageDecommitted;
|
|
|
+
|
|
|
+ // Back-off from decommit if we are trying to enter IdleDecommit again.
|
|
|
+ if (this->waitingToEnterIdleDecommit)
|
|
|
+ {
|
|
|
+ break;
|
|
|
+ }
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- // decommit pages that are empty
|
|
|
-
|
|
|
- while (pageToDecommit > 0 && !emptySegments.Empty())
|
|
|
+ // decommit pages that are empty.
|
|
|
+ // back-off from decommit if we are trying to enter IdleDecommit again.
|
|
|
+ while (!this->waitingToEnterIdleDecommit && pageToDecommit > 0 && !emptySegments.Empty())
|
|
|
{
|
|
|
if (pageToDecommit >= maxAllocPageCount)
|
|
|
{
|
|
|
@@ -2131,6 +2150,7 @@ PageAllocatorBase<TVirtualAlloc, TSegment, TPageSegment>::DecommitNow(bool all)
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+ if(!this->waitingToEnterIdleDecommit)
|
|
|
{
|
|
|
typename DListBase<TPageSegment>::EditingIterator i(&segments);
|
|
|
|
|
|
@@ -2146,23 +2166,34 @@ PageAllocatorBase<TVirtualAlloc, TSegment, TPageSegment>::DecommitNow(bool all)
|
|
|
i.MoveCurrentTo(&decommitSegments);
|
|
|
pageToDecommit -= pageDecommitted;
|
|
|
|
|
|
+ // Back-off from decommit if we are trying to enter IdleDecommit again.
|
|
|
+ if (this->waitingToEnterIdleDecommit)
|
|
|
+ {
|
|
|
+ break;
|
|
|
+ }
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- Assert(pageToDecommit == 0);
|
|
|
-
|
|
|
+ Assert(pageToDecommit == 0 || this->waitingToEnterIdleDecommit);
|
|
|
+#if DBG
|
|
|
+ if (pageToDecommit != 0 && this->waitingToEnterIdleDecommit)
|
|
|
+ {
|
|
|
+ this->idleDecommitBackOffCount++;
|
|
|
+ }
|
|
|
+#endif
|
|
|
|
|
|
#if DBG_DUMP
|
|
|
- Assert(this->freePageCount == newFreePageCount + decommitCount);
|
|
|
+ Assert(this->freePageCount == newFreePageCount + decommitCount + pageToDecommit);
|
|
|
#endif
|
|
|
|
|
|
- this->freePageCount = newFreePageCount;
|
|
|
+ // If we had to back-off from decommiting then we may still have some free pages left to decommit.
|
|
|
+ this->freePageCount = newFreePageCount + pageToDecommit;
|
|
|
|
|
|
#ifdef ENABLE_BASIC_TELEMETRY
|
|
|
if (this->decommitStats != nullptr)
|
|
|
{
|
|
|
this->decommitStats->numPagesDecommitted += decommitCount;
|
|
|
- this->decommitStats->numFreePageCount += newFreePageCount;
|
|
|
+ this->decommitStats->numFreePageCount += newFreePageCount + pageToDecommit;
|
|
|
}
|
|
|
#endif
|
|
|
|