@@ -247,6 +247,7 @@ class MapAllocatorCache {
247247 // The cache is initially empty
248248 LRUHead = CachedBlock::InvalidEntry;
249249 LRUTail = CachedBlock::InvalidEntry;
250+ LastUnreleasedEntry = CachedBlock::InvalidEntry;
250251
251252 // Available entries will be retrieved starting from the beginning of the
252253 // Entries array
@@ -321,9 +322,10 @@ class MapAllocatorCache {
321322 }
322323 CachedBlock PrevEntry = Quarantine[QuarantinePos];
323324 Quarantine[QuarantinePos] = Entry;
324- if (OldestTime == 0 )
325- OldestTime = Entry.Time ;
326325 Entry = PrevEntry;
326+ // Update the entry time to reflect the time that the
327+ // quarantined memory is placed in the Entries array
328+ Entry.Time = Time;
327329 }
328330
329331 // All excess entries are evicted from the cache
@@ -334,9 +336,6 @@ class MapAllocatorCache {
334336 }
335337
336338 insert (Entry);
337-
338- if (OldestTime == 0 )
339- OldestTime = Entry.Time ;
340339 } while (0 );
341340
342341 for (MemMapT &EvictMemMap : EvictionMemMaps)
@@ -535,6 +534,9 @@ class MapAllocatorCache {
535534 Entries[LRUHead].Prev = static_cast <u16 >(FreeIndex);
536535 }
537536
537+ if (LastUnreleasedEntry == CachedBlock::InvalidEntry)
538+ LastUnreleasedEntry = static_cast <u16 >(FreeIndex);
539+
538540 Entries[FreeIndex] = Entry;
539541 Entries[FreeIndex].Next = LRUHead;
540542 Entries[FreeIndex].Prev = CachedBlock::InvalidEntry;
@@ -552,6 +554,9 @@ class MapAllocatorCache {
552554
553555 Entries[I].invalidate ();
554556
557+ if (I == LastUnreleasedEntry)
558+ LastUnreleasedEntry = Entries[LastUnreleasedEntry].Prev ;
559+
555560 if (I == LRUHead)
556561 LRUHead = Entries[I].Next ;
557562 else
@@ -593,35 +598,37 @@ class MapAllocatorCache {
593598 }
594599 }
595600
596- void releaseIfOlderThan (CachedBlock &Entry, u64 Time) REQUIRES(Mutex) {
597- if (!Entry.isValid () || !Entry.Time )
598- return ;
599- if (Entry.Time > Time) {
600- if (OldestTime == 0 || Entry.Time < OldestTime)
601- OldestTime = Entry.Time ;
602- return ;
603- }
601+ inline void release (CachedBlock &Entry) {
602+ DCHECK (Entry.Time != 0 );
604603 Entry.MemMap .releaseAndZeroPagesToOS (Entry.CommitBase , Entry.CommitSize );
605604 Entry.Time = 0 ;
606605 }
607606
608607 void releaseOlderThan (u64 Time) EXCLUDES(Mutex) {
609608 ScopedLock L (Mutex);
610- if (!EntriesCount || OldestTime == 0 || OldestTime > Time )
609+ if (!EntriesCount)
611610 return ;
612- OldestTime = 0 ;
613- for (uptr I = 0 ; I < Config::getQuarantineSize (); I++)
614- releaseIfOlderThan (Quarantine[I], Time);
615- for (uptr I = 0 ; I < Config::getEntriesArraySize (); I++)
616- releaseIfOlderThan (Entries[I], Time);
617- }
618611
612+ for (uptr I = 0 ; I < Config::getQuarantineSize (); I++) {
613+ CachedBlock &ReleaseEntry = Quarantine[I];
614+ if (!ReleaseEntry.isValid () || !ReleaseEntry.Time ||
615+ ReleaseEntry.Time > Time)
616+ continue ;
617+ release (ReleaseEntry);
618+ }
619+
620+ // Release oldest entries first by releasing from decommit base
621+ while (LastUnreleasedEntry != CachedBlock::InvalidEntry &&
622+ Entries[LastUnreleasedEntry].Time <= Time) {
623+ release (Entries[LastUnreleasedEntry]);
624+ LastUnreleasedEntry = Entries[LastUnreleasedEntry].Prev ;
625+ }
626+ }
619627 HybridMutex Mutex;
620628 u32 EntriesCount GUARDED_BY (Mutex) = 0;
621629 u32 QuarantinePos GUARDED_BY (Mutex) = 0;
622630 atomic_u32 MaxEntriesCount = {};
623631 atomic_uptr MaxEntrySize = {};
624- u64 OldestTime GUARDED_BY (Mutex) = 0;
625632 atomic_s32 ReleaseToOsIntervalMs = {};
626633 u32 CallsToRetrieve GUARDED_BY (Mutex) = 0;
627634 u32 SuccessfulRetrieves GUARDED_BY (Mutex) = 0;
@@ -636,6 +643,9 @@ class MapAllocatorCache {
636643 u16 LRUTail GUARDED_BY (Mutex) = 0;
637644 // The AvailableHead is the top of the stack of available entries
638645 u16 AvailableHead GUARDED_BY (Mutex) = 0;
646+ // The LastUnreleasedEntry is the least recently used entry that has not
647+ // been released
648+ u16 LastUnreleasedEntry GUARDED_BY (Mutex) = 0;
639649};
640650
641651template <typename Config> class MapAllocator {
0 commit comments