diff --git a/src/common/objects/dobject.cpp b/src/common/objects/dobject.cpp index 9f4a164e44..8516229dee 100644 --- a/src/common/objects/dobject.cpp +++ b/src/common/objects/dobject.cpp @@ -229,6 +229,7 @@ DObject::DObject () ObjNext = GC::Root; GCNext = nullptr; GC::Root = this; + GC::AllocCount++; } DObject::DObject (PClass *inClass) @@ -238,6 +239,7 @@ DObject::DObject (PClass *inClass) ObjNext = GC::Root; GCNext = nullptr; GC::Root = this; + GC::AllocCount++; } //========================================================================== @@ -275,6 +277,7 @@ DObject::~DObject () void DObject::Release() { + if (GC::AllocCount > 0) GC::AllocCount--; DObject **probe; // Unlink this object from the GC list. diff --git a/src/common/objects/dobjgc.cpp b/src/common/objects/dobjgc.cpp index 9afa0b0af0..58b27c4b76 100644 --- a/src/common/objects/dobjgc.cpp +++ b/src/common/objects/dobjgc.cpp @@ -108,6 +108,7 @@ namespace GC size_t AllocBytes; size_t Threshold; size_t Estimate; +size_t AllocCount; DObject *Gray; DObject *Root; DObject *SoftRoots; diff --git a/src/common/objects/dobjgc.h b/src/common/objects/dobjgc.h index e3f8b85b14..d01e52cf63 100644 --- a/src/common/objects/dobjgc.h +++ b/src/common/objects/dobjgc.h @@ -43,6 +43,9 @@ namespace GC // Number of bytes currently allocated through M_Malloc/M_Realloc. extern size_t AllocBytes; + // Number of allocated objects since last CheckGC call. + extern size_t AllocCount; + // Amount of memory to allocate before triggering a collection. extern size_t Threshold; @@ -105,10 +108,15 @@ namespace GC } // Check if it's time to collect, and do a collection step if it is. - static inline void CheckGC() + static inline bool CheckGC() { + AllocCount = 0; if (AllocBytes >= Threshold) + { Step(); + return true; + } + return false; } // Forces a collection to start now. diff --git a/src/g_game.cpp b/src/g_game.cpp index fdbc18aa80..f394d1a855 100644 --- a/src/g_game.cpp +++ b/src/g_game.cpp @@ -1316,6 +1316,15 @@ void G_Ticker () default: break; } + // Do some more aggressive GC maintenance when the game ticker is inactive. + if ((gamestate != GS_LEVEL && gamestate != GS_TITLELEVEL) || paused || P_CheckTickerPaused()) + { + size_t ac = std::max(10, GC::AllocCount); + for (size_t i = 0; i < ac; i++) + { + if (!GC::CheckGC()) break; + } + } // [MK] Additional ticker for UI events right after all others primaryLevel->localEventManager->PostUiTick();