@@ -244,6 +244,7 @@ class MapAllocatorCache {
244244 // The cache is initially empty
245245 LRUHead = CachedBlock::InvalidEntry;
246246 LRUTail = CachedBlock::InvalidEntry;
247+ LastUnreleasedEntry = CachedBlock::InvalidEntry;
247248
248249 // Available entries will be retrieved starting from the beginning of the
249250 // Entries array
@@ -318,9 +319,10 @@ class MapAllocatorCache {
318319 }
319320 CachedBlock PrevEntry = Quarantine[QuarantinePos];
320321 Quarantine[QuarantinePos] = Entry;
321- if (OldestTime == 0 )
322- OldestTime = Entry.Time ;
323322 Entry = PrevEntry;
323+ // Update the entry time to reflect the time that the
324+ // quarantined memory is placed in the Entries array
325+ Entry.Time = Time;
324326 }
325327
326328 // All excess entries are evicted from the cache
@@ -331,9 +333,6 @@ class MapAllocatorCache {
331333 }
332334
333335 insert (Entry);
334-
335- if (OldestTime == 0 )
336- OldestTime = Entry.Time ;
337336 } while (0 );
338337
339338 for (MemMapT &EvictMemMap : EvictionMemMaps)
@@ -532,6 +531,9 @@ class MapAllocatorCache {
532531 Entries[LRUHead].Prev = static_cast <u16 >(FreeIndex);
533532 }
534533
534+ if (LastUnreleasedEntry == CachedBlock::InvalidEntry)
535+ LastUnreleasedEntry = static_cast <u16 >(FreeIndex);
536+
535537 Entries[FreeIndex] = Entry;
536538 Entries[FreeIndex].Next = LRUHead;
537539 Entries[FreeIndex].Prev = CachedBlock::InvalidEntry;
@@ -549,6 +551,9 @@ class MapAllocatorCache {
549551
550552 Entries[I].invalidate ();
551553
554+ if (I == LastUnreleasedEntry)
555+ LastUnreleasedEntry = Entries[LastUnreleasedEntry].Prev ;
556+
552557 if (I == LRUHead)
553558 LRUHead = Entries[I].Next ;
554559 else
@@ -590,35 +595,37 @@ class MapAllocatorCache {
590595 }
591596 }
592597
593- void releaseIfOlderThan (CachedBlock &Entry, u64 Time) REQUIRES(Mutex) {
594- if (!Entry.isValid () || !Entry.Time )
595- return ;
596- if (Entry.Time > Time) {
597- if (OldestTime == 0 || Entry.Time < OldestTime)
598- OldestTime = Entry.Time ;
599- return ;
600- }
598+ inline void release (CachedBlock &Entry) {
599+ DCHECK (Entry.Time != 0 );
601600 Entry.MemMap .releaseAndZeroPagesToOS (Entry.CommitBase , Entry.CommitSize );
602601 Entry.Time = 0 ;
603602 }
604603
605604 void releaseOlderThan (u64 Time) EXCLUDES(Mutex) {
606605 ScopedLock L (Mutex);
607- if (!EntriesCount || OldestTime == 0 || OldestTime > Time )
606+ if (!EntriesCount)
608607 return ;
609- OldestTime = 0 ;
610- for (uptr I = 0 ; I < Config::getQuarantineSize (); I++)
611- releaseIfOlderThan (Quarantine[I], Time);
612- for (uptr I = 0 ; I < Config::getEntriesArraySize (); I++)
613- releaseIfOlderThan (Entries[I], Time);
614- }
615608
609+ for (uptr I = 0 ; I < Config::getQuarantineSize (); I++) {
610+ CachedBlock &ReleaseEntry = Quarantine[I];
611+ if (!ReleaseEntry.isValid () || !ReleaseEntry.Time ||
612+ ReleaseEntry.Time > Time)
613+ continue ;
614+ release (ReleaseEntry);
615+ }
616+
617+ // Release oldest entries first by releasing from decommit base
618+ while (LastUnreleasedEntry != CachedBlock::InvalidEntry &&
619+ Entries[LastUnreleasedEntry].Time <= Time) {
620+ release (Entries[LastUnreleasedEntry]);
621+ LastUnreleasedEntry = Entries[LastUnreleasedEntry].Prev ;
622+ }
623+ }
616624 HybridMutex Mutex;
617625 u32 EntriesCount GUARDED_BY (Mutex) = 0;
618626 u32 QuarantinePos GUARDED_BY (Mutex) = 0;
619627 atomic_u32 MaxEntriesCount = {};
620628 atomic_uptr MaxEntrySize = {};
621- u64 OldestTime GUARDED_BY (Mutex) = 0;
622629 atomic_s32 ReleaseToOsIntervalMs = {};
623630 u32 CallsToRetrieve GUARDED_BY (Mutex) = 0;
624631 u32 SuccessfulRetrieves GUARDED_BY (Mutex) = 0;
@@ -633,6 +640,9 @@ class MapAllocatorCache {
633640 u16 LRUTail GUARDED_BY (Mutex) = 0;
634641 // The AvailableHead is the top of the stack of available entries
635642 u16 AvailableHead GUARDED_BY (Mutex) = 0;
643+ // The LastUnreleasedEntry is the least recently used entry that has not
644+ // been released
645+ u16 LastUnreleasedEntry GUARDED_BY (Mutex) = 0;
636646};
637647
638648template <typename Config> class MapAllocator {
0 commit comments