In a PHP CLI software, we are facing serious memory leakage due to a lot of rotten code, both accumulated in our own software and third-party plugins for our software.Currently, the object references look like this:class Server{    // the central singleton object    /** @var Level[] */    public $levels;    /** @var Player[] */    public $players;}class Level{    /** @var Entity[] */    public $entities;}class Player extends Entity{}Normal Entity objects are specific to a certain Level, but Player objects can transfer between levels. Player objects are also often accessed beyond the Level scope (they even belong to none when initializing and finalizing), while other Entity objects are usually closely related to Level object, thus the extra players field in Server.All Entity objects frequently get constructed or destructed. However, as mentioned above, bad code makes it very likely to have memory leak.I have considered an extensive use of WeakRef to mitigate the problem, but due to various technical reasons, we are not using the weakref extension. Instead, I am considering replacing all Entity references with an entity ID, which is unique for each instance throughout the whole runtime. This is currently the key used for the Server::$players and Level::$entities maps. The Entity objects will be appropriately deleted and hence permanently dereferenced thus collected by GC. I don't care about the rest broken links; they'll have null pointer problems, so we can fix them one by one more easily.If this happens, we can have 4 approaches to access an entity by entity ID:1. Global entity storageMake a field in Server to store all Entity instances mapped by entity IDs. Search by $server->globalEntityStore[$entityId].2. Iterate levelIterate through all levels in the server until an entity instance is found in the Level::$entities field in one of the levels.3. Pass entity ID + level IDThis is very inefficient. We will end up having to pass/store two data every time we passed an Entity object before. Will I end up making a class EntityReference{ $entityId, $levelId } to pass it? Feels even worse...4. Store an entityId->levelId in Server classThis feels useless, as it's almost same as #1.Note that the number of entities in each level often becomes numerous (compared to the frequency that the search for an Entity instance will take place), while the number of Level objects is low.For concrete reference (not much value actually), the usual numbers: below 10 levels in a server (i.e. in a runtime, as it is singleton), up to 100 players in a server, up to thousands of entities or more in each level. Server is run tick-based, i.e. a cycle must complete within 50 milliseconds. Is there any other solution I should consider? Or, among the 4 approaches, what are the pros and cons?
De facto weak reference centralized object storage
design patterns;object oriented design;singleton;memory usage;weak references