I'm happy to report that I was able to resolve this issue. It was not a memory leak nor was it related to fixes in the 5.x series.
Rather it was a bug with mapblocks being continuously reloaded at the world border even after they were already in memory causing the associated static objects to be multiplied exponentially. So it was an unusual confluence of factors (two different bugs), hence why it never became apparent until exactly the right conditions were met.
Code: Select all
2025-01-30 12:56:20: ACTION[Server]: Recording login time for player sorcerykid
2025-01-30 12:56:20: ACTION[Server]: sorcerykid spawns at (-2148.3200683594,5.6659998893738,30927.201171875)
2025-01-30 12:56:22: ERROR[Server]: suspiciously large amount of objects detected: 460784 in (-135,-2,1933); removing all of them.
2025-01-30 12:56:22: ERROR[Server]: suspiciously large amount of objects detected: 328320 in (-134,-2,1933); removing all of them.
2025-01-30 13:07:45: ERROR[Main]: ServerEnv: Trying to store id=13 statically but block (-134,-2,1933) already contains 10046592 objects.
Thankfully I deduced from the onset that the cause was related to excessive objects in mapblocks. I was just wrong about the source. It was not items intentionally dropped by players, but rather the temporary entities that I was using in my Ambience II mod to track placement of environmental sounds in mapblocks surrounding each player.
This proved to be a situation where my RocketLib Toolkit was indispensible. I was able to put togther a quick script to locate all mapblocks with unusually large numbers of objects.
Code: Select all
local maplib = require "maplib"
local source_path = assert( arg[ 1 ] )
local decode_pos = maplib.decode_pos
local pos_to_string = maplib.pos_to_string
local map_db = MapDatabase( source_path, false )
for index, block in map_db.iterate( ) do
local fpos = decode_pos( index )
local counts = { }
for i, v in ipairs( block.object_list ) do
local count = counts[ v.name ]
counts[ v.name ] = count and count + 1 or 1
end
if #block.object_list > 100 then
for k, v in pairs( counts ) do
print( string.format( "Found: %d of %s", v, k ) )
end
print( string.format( "%d total objects in mapblock %s",
#block.object_list, pos_to_string( decode_pos( index ) ) ) )
end
end
Of course, it was immediately apparent that the objects from my Ambience II mod were being duplicated outside the world border, but nowhere else. So the real puzzle at that point was to determine why.
My biggest fear was that I somehow had introduced a bug in my fork of the engine. So I scoured the CPP source for an entire day, double-checking every instance where static objects were being stored, and nothing stood out as unusual.
To eliminate any possibility that this bug was specific to my fork, i compiled a clean version of Minetest 0.4.14-stable from source. Yet the problem persisted. I then compiled a clean version of Minetest 0.4.15-dev and the problem altogether disappeared. That afforded some sense of relief, even though it still didn't solve the mystery.
So I was one step closer to a resolution, yet I still needed to determine at which point the bug had been fixed. There were a myriad of commits relating to world border oddities in Minetest 0.4.15, but none of them referenced this issue specifically. I realized the only choice was to work backwards day-by-day through the commit history, compiling and retesting until I could identify the commit responsible.
After several hours of research, I managed to narrow it down to one commit titled "Fix unnecessary block loading". Yet nowhere in the commit message itself was there any mention of duplicating objects or excessive memory use. Thankfully, I checked the associated PR because not only did the title specifically reference duplicating objects, but the comments and even a related issue also confirmed this was was the correct fix.
Ultimately I ended up patching my fork with
PR #4847 and
PR #4888, both of which specifically addressed this issue. That has sense completely solved the out of memory errors :)