
Memory Leak: CoreEntityManager#entityMapGlobal Retaining Removed Entities
ByThePowerOfScience opened this issue ยท 3 comments
Describe the bug
Heap dump showed large memory usage by adaptiveperformancetweakscore.entity.CoreEntityManager
(3 GB) on my dedicated server, with 2 GB taken up by entityMapGlobal
. Looking through the entries in the map and its submaps showed that it was retaining a massive number of references to entities that had been removed by being unloaded to the chunk, causing the bloated size.
You should make sure the values of the submaps are WeakReference
s so they don't stop the entities from being garbage-collected.
Screenshots
The heap dump from my server, with the largest dominator being the entityMapGlobal
map.
The removal reasons for each element of that prehistoricfauna:dermestid_beetle
entry in the map. (Each of those addresses corresponds to the RemovalReason.UNLOADED_TO_CHUNK
enum object.)
I can also send you the full heap dump if you'd like; DM me on Discord at @abadhaiku
and we'll work something out. It's 2 GB even compressed, so I can't send it here.
Thanks for the report and screenshots.
Could you please share the:
- AdaptivePerformanceTweaksCore version
- Minecraft version and loader (Forge, NeoForge, or Fabric)
Current builds already clean up removed or unloaded entities every 500 ticks, including UNLOADED_TO_CHUNK
:
// Remove entities which are no longer valid like removed entities.
for (Set<Entity> entities : entityMapToCheck.values()) {
Iterator<Entity> entityIterator = entities.iterator();
while (entityIterator.hasNext()) {
// Check if the entity is still valid.
Entity entity = entityIterator.next();
if (entity == null || entity.isRemoved()) {
entityIterator.remove();
removedEntries++;
}
}
}
With debug mode on you should see:
[Entity Manager] Removed N entities from overview, N from chunk overview, N from world overview and N from global overview.
About WeakReference
: good idea, but it will not fully fix the issue because the map still keeps the key string.
The periodic sweep above is needed to remove both the key and the value from the map.
I can still add WeakReferences to reduce memory between sweeps, but the cleanup pass is what guarantees full removal.
However I found another potential cause. To confirm whether it is related, please share the exact version in which you are experiencing the issue. Thanks.
Using APT 11.3.0 on Forge 1.20.1.
Also, I see exactly what you're talking about in the code, and you're totally right that this shouldn't happen. I think I might see the problem, though?
I think what's happening is that the event.haveTime()
check results in a feedback loop where, when the memory usage gets so high that it slows down the tick time, it never runs verifyEntities
and can never free the memory.
Sorry for the bad reports here btw. I had just gotten woken up by the server owner freaking out that it was maxing out memory and I was kinda frazzled.
Thanks for the feedback and the additional context. I prepared a fix that runs a cleanup every 5 minutes when the server has spare resources, and after every 500 new entries.
I also added additional cleanup steps to ensure objects are dereferenced and eligible for GC.
If the server is constantly at 100% utilization and the cleanup cannot run, this needs a deeper investigation.
Under normal load, especially with few or no players online, the server should have enough headroom to run the task.