From 4aa272d4293af7719a3a375bbea19f0eaf0172a7 Mon Sep 17 00:00:00 2001 From: Kamron Batman <3953314+kamronbatman@users.noreply.github.com> Date: Tue, 15 Apr 2025 19:14:45 -0700 Subject: [PATCH] feat: Adds an Item/Mobile memory leak detector. Fixes minor leak in doors. (#2159) ### Summary Adds the command [TrackLeaks to enable tracking item/mobiles that have been deleted but still have dangling references. Requires adding the _TRACK_LEAKS_ define constant during build. --- Projects/Server/EntityFinalizationTracker.cs | 177 ++++++++++++++++++ .../GarbageCollection/Gen2GcCallback.cs | 48 ++++- Projects/Server/Items/Item.cs | 9 +- Projects/Server/Mobiles/Mobile.cs | 7 + Projects/Server/World/World.cs | 5 + .../Items/SchmendrickApprenticeCorpse.cs | 4 + .../Items/Construction/Doors/BaseDoor.cs | 13 ++ .../UOContent/Items/Misc/Corpses/Corpse.cs | 2 +- docs/commands/commands.7z | Bin 12687 -> 12498 bytes 9 files changed, 256 insertions(+), 9 deletions(-) create mode 100644 Projects/Server/EntityFinalizationTracker.cs diff --git a/Projects/Server/EntityFinalizationTracker.cs b/Projects/Server/EntityFinalizationTracker.cs new file mode 100644 index 000000000..75d4efa9c --- /dev/null +++ b/Projects/Server/EntityFinalizationTracker.cs @@ -0,0 +1,177 @@ +/************************************************************************* + * ModernUO * + * Copyright 2019-2025 - ModernUO Development Team * + * Email: hi@modernuo.com * + * File: EntityFinalizationTracker.cs * + * * + * This program is free software: you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation, either version 3 of the License, or * + * (at your option) any later version. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program. If not, see . * + *************************************************************************/ + +using System; +using System.Collections.Generic; +using System.Runtime.CompilerServices; +using System.Threading; +using Server.Logging; + +namespace Server; + +public static class EntityFinalizationTracker +{ + private static readonly ILogger logger = LogFactory.GetLogger(typeof(EntityFinalizationTracker)); + + private sealed record TrackedEntity(WeakReference Reference, int ReferenceHash, DateTime RemovedAt); + + private static readonly Lock _sync = new(); + private static bool _enabled; + private static DateTime _nextCheck = DateTime.MinValue; + +#if TRACK_LEAKS + private const bool CanBeEnabled = true; +#else + private const bool CanBeEnabled = false; +#endif + + public static void Configure() + { + CommandSystem.Register("gc", AccessLevel.Administrator, _ => GC.Collect(GC.MaxGeneration, GCCollectionMode.Forced, blocking: true, compacting: true)); + CommandSystem.Register("TrackLeaks", AccessLevel.Developer, TrackLeaks_OnCommand); + } + + [Usage("TrackLeaks ")] + [Description("Enables or disables entity leak tracking. May impact performance and should be used only when necessary!")] + private static void TrackLeaks_OnCommand(CommandEventArgs e) + { + var from = e.Mobile; + if (!CanBeEnabled) { + from.SendMessage("Entity leak tracking is not enabled in this build. Rebuild with TRACK_LEAKS defined."); + return; + } + + if (e.Arguments.Length == 0) + { + from.SendMessage("Usage: TrackLeaks "); + return; + } + + var enable = Utility.ToBoolean(e.Arguments[0]); + var status = enable ? "enabled" : "disabled"; + if (enable == _enabled) + { + from.SendMessage($"Entity leak tracking already {status}."); + return; + } + + if (_enabled) + { + EnableLeakTracking(from); + } + else + { + DisableLeakTracking(from); + } + } + + private static void EnableLeakTracking(Mobile from) + { + if (_enabled) + { + return; + } + + _enabled = true; + Gen2GcCallback.Register(() => + { + CheckLeaks(); + return _enabled; + }); + + from.SendMessage("Entity leak tracking enabled."); + logger.Warning("Entity leak tracking enabled by {Name} ({Serial:X8})", from.Name, from.Serial); + } + + private static void DisableLeakTracking(Mobile from) + { + if (!_enabled) + { + return; + } + + _enabled = false; + from.SendMessage("Entity leak tracking disabled."); + logger.Warning("Entity leak tracking disabled by {Name} ({Serial:X8})", from.Name, from.Serial); + } + + private static readonly List _entities = []; + private static readonly HashSet _finalizedHashes = []; + + public static void TrackEntity(T entity) where T : IEntity + { + lock (_sync) + { + var hash = RuntimeHelpers.GetHashCode(entity); + _entities.Add(new TrackedEntity(new WeakReference(entity), hash, Core.Now)); + } + } + + public static void NotifyFinalized(object entity) + { + lock (_sync) + { + _finalizedHashes.Add(RuntimeHelpers.GetHashCode(entity)); + } + } + + private static void CheckLeaks() + { + if (_entities.Count == 0) + { + return; + } + + var now = Core.Now; + if (now <= _nextCheck) + { + return; + } + + _nextCheck = now + TimeSpan.FromMinutes(2); + + _entities.RemoveAll(entry => + { + if (_finalizedHashes.Remove(entry.ReferenceHash)) + { + return true; + } + + if (!entry.Reference.TryGetTarget(out var obj) || obj is not IEntity entity) + { + return true; + } + + if (ExceptionToLeakCheck(entity)) + { + return false; + } + + var duration = now - entry.RemovedAt; + + if (duration <= TimeSpan.FromSeconds(120)) + { + return false; + } + + logger.Warning("[Leak Warning] {Name} ({Serial:X8}) collected but not finalized after {Duration}.", entity.GetType().Name, entity.Serial, duration); + return false; + }); + } + + private static bool ExceptionToLeakCheck(IEntity entity) => + // Mobiles that are deleted, but have a reference to a corpse that is not deleted should be exempt + (entity as Mobile)?.Corpse?.Deleted == false; +} diff --git a/Projects/Server/GarbageCollection/Gen2GcCallback.cs b/Projects/Server/GarbageCollection/Gen2GcCallback.cs index fc23db8ce..97b4b91ff 100644 --- a/Projects/Server/GarbageCollection/Gen2GcCallback.cs +++ b/Projects/Server/GarbageCollection/Gen2GcCallback.cs @@ -13,18 +13,31 @@ namespace System; /// internal sealed class Gen2GcCallback : CriticalFinalizerObject { - private readonly Func _callback; + private readonly Func? _callback0; + private readonly Func? _callback1; private GCHandle _weakTargetObj; + private Gen2GcCallback(Func callback) => _callback0 = callback; + private Gen2GcCallback(Func callback, object targetObj) { - _callback = callback; + _callback1 = callback; _weakTargetObj = GCHandle.Alloc(targetObj, GCHandleType.Weak); } /// /// Schedule 'callback' to be called in the next GC. If the callback returns true it is - /// rescheduled for the next Gen 2 GC. Otherwise the callbacks stop. + /// rescheduled for the next Gen 2 GC, otherwise the callback stops. + /// + public static void Register(Func callback) + { + // Create an unreachable object that remembers the callback function and target object. + new Gen2GcCallback(callback); + } + + /// + /// Schedule 'callback' to be called in the next GC. If the callback returns true it is + /// rescheduled for the next Gen 2 GC, otherwise the callback stops. /// /// NOTE: This callback will be kept alive until either the callback function returns false, /// or the target object dies. @@ -51,8 +64,8 @@ internal sealed class Gen2GcCallback : CriticalFinalizerObject // Execute the callback method. try { - Debug.Assert(_callback != null); - if (_callback?.Invoke(targetObj) != true) + Debug.Assert(_callback1 != null); + if (!_callback1(targetObj)) { // If the callback returns false, this callback object is no longer needed. _weakTargetObj.Free(); @@ -63,8 +76,29 @@ internal sealed class Gen2GcCallback : CriticalFinalizerObject { // Ensure that we still get a chance to resurrect this object, even if the callback throws an exception. #if DEBUG - // Except in DEBUG, as we really shouldn't be hitting any exceptions here. - throw; + // Except in DEBUG, as we really shouldn't be hitting any exceptions here. + throw; +#endif + } + } + else + { + // Execute the callback method. + try + { + Debug.Assert(_callback0 != null); + if (!_callback0()) + { + // If the callback returns false, this callback object is no longer needed. + return; + } + } + catch + { + // Ensure that we still get a chance to resurrect this object, even if the callback throws an exception. +#if DEBUG + // Except in DEBUG, as we really shouldn't be hitting any exceptions here. + throw; #endif } } diff --git a/Projects/Server/Items/Item.cs b/Projects/Server/Items/Item.cs index 0fd0dc0bd..9726e1d34 100644 --- a/Projects/Server/Items/Item.cs +++ b/Projects/Server/Items/Item.cs @@ -328,7 +328,7 @@ public class Item : IHued, IComparable, ISpawnable, IObjectPropertyListEnt public virtual TimeSpan DecayTime => DefaultDecayTime; [CommandProperty(AccessLevel.GameMaster)] - public virtual bool Decays => Movable && Visible && Spawner == null; + public virtual bool Decays => Movable && Visible && Spawner == null; public DateTime LastMoved { get; set; } @@ -3268,6 +3268,13 @@ public class Item : IHued, IComparable, ISpawnable, IObjectPropertyListEnt } } +#if TRACK_LEAKS + ~Item() + { + EntityFinalizationTracker.NotifyFinalized(this); + } +#endif + public virtual void OnDelete() { if (Spawner != null) diff --git a/Projects/Server/Mobiles/Mobile.cs b/Projects/Server/Mobiles/Mobile.cs index e82692ab0..2650ef58e 100644 --- a/Projects/Server/Mobiles/Mobile.cs +++ b/Projects/Server/Mobiles/Mobile.cs @@ -4574,6 +4574,13 @@ public partial class Mobile : IHued, IComparable, ISpawnable, IObjectPro } } +#if TRACK_LEAKS + ~Mobile() + { + EntityFinalizationTracker.NotifyFinalized(this); + } +#endif + /// /// Overridable. Virtual event invoked before the Mobile is deleted. /// diff --git a/Projects/Server/World/World.cs b/Projects/Server/World/World.cs index 14a5ba31f..a8ecb665d 100644 --- a/Projects/Server/World/World.cs +++ b/Projects/Server/World/World.cs @@ -492,7 +492,12 @@ public static class World else { logger.Warning($"Attempted to call World.RemoveEntity with '{entity.GetType()}'. Must be a mobile or item."); + return; } + +#if TRACK_LEAKS + EntityFinalizationTracker.TrackEntity(entity); +#endif } [MethodImpl(MethodImplOptions.AggressiveInlining)] diff --git a/Projects/UOContent/Engines/Quests/Uzeraan Turmoil/Items/SchmendrickApprenticeCorpse.cs b/Projects/UOContent/Engines/Quests/Uzeraan Turmoil/Items/SchmendrickApprenticeCorpse.cs index 33793a202..20b213646 100644 --- a/Projects/UOContent/Engines/Quests/Uzeraan Turmoil/Items/SchmendrickApprenticeCorpse.cs +++ b/Projects/UOContent/Engines/Quests/Uzeraan Turmoil/Items/SchmendrickApprenticeCorpse.cs @@ -27,6 +27,8 @@ public partial class SchmendrickApprenticeCorpse : Corpse _lantern = new Lantern { Movable = false, Protected = true }; _lantern.Ignite(); + + Owner = null; } private static Mobile GetOwner() @@ -152,5 +154,7 @@ public partial class SchmendrickApprenticeCorpse : Corpse { _lantern.Delete(); } + + Owner?.Delete(); } } diff --git a/Projects/UOContent/Items/Construction/Doors/BaseDoor.cs b/Projects/UOContent/Items/Construction/Doors/BaseDoor.cs index 5997ab735..07796c900 100644 --- a/Projects/UOContent/Items/Construction/Doors/BaseDoor.cs +++ b/Projects/UOContent/Items/Construction/Doors/BaseDoor.cs @@ -423,6 +423,13 @@ public abstract partial class BaseDoor : Item, ILockable, ITelekinesisable } } + public override void OnDelete() + { + _timer?.Stop(); + _timer = null; + Link = null; + } + [AfterDeserialization] private void AfterDeserialization() { @@ -442,6 +449,12 @@ public abstract partial class BaseDoor : Item, ILockable, ITelekinesisable protected override void OnTick() { + if (_door.Deleted) + { + Stop(); + return; + } + if (_door.Open && _door.IsFreeToClose()) { _door.Open = false; diff --git a/Projects/UOContent/Items/Misc/Corpses/Corpse.cs b/Projects/UOContent/Items/Misc/Corpses/Corpse.cs index 8ea7d1319..4c093f8f0 100644 --- a/Projects/UOContent/Items/Misc/Corpses/Corpse.cs +++ b/Projects/UOContent/Items/Misc/Corpses/Corpse.cs @@ -109,7 +109,7 @@ public partial class Corpse : Container, ICarvable [SerializableField(7, setter: "private")] private List _aggressors; - [SerializableField(8, setter: "private")] + [SerializableField(8, setter: "protected")] [SerializedCommandProperty(AccessLevel.GameMaster)] private Mobile _owner; diff --git a/docs/commands/commands.7z b/docs/commands/commands.7z index d0d6c0e9bbb930aa761d0a8231b619b1ad87724e..6597b7832dec5c20d9e7267513bb02db730bb83d 100644 GIT binary patch delta 9840 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 W5_SUvXmqaI0Tl)T03ZMW0001b`yHtO delta 10030 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 E0DdBdJOBUy