diff --git a/src/Umbraco.Core/CoreBootManager.cs b/src/Umbraco.Core/CoreBootManager.cs index 00e0daebc8..03a5206522 100644 --- a/src/Umbraco.Core/CoreBootManager.cs +++ b/src/Umbraco.Core/CoreBootManager.cs @@ -241,6 +241,8 @@ namespace Umbraco.Core // we're ready to serve content! ApplicationContext.IsReady = true; + //And now we can dispose of our startup handlers - save some memory + ApplicationEventsResolver.Current.Dispose(); //stop the timer and log the output _timer.Dispose(); diff --git a/src/Umbraco.Core/ObjectResolution/ApplicationEventsResolver.cs b/src/Umbraco.Core/ObjectResolution/ApplicationEventsResolver.cs index 875fcd051f..3d1d44133b 100644 --- a/src/Umbraco.Core/ObjectResolution/ApplicationEventsResolver.cs +++ b/src/Umbraco.Core/ObjectResolution/ApplicationEventsResolver.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using System.Linq; +using System.Threading; using umbraco.interfaces; namespace Umbraco.Core.ObjectResolution @@ -8,7 +9,10 @@ namespace Umbraco.Core.ObjectResolution /// /// A resolver to return all IApplicationEvents objects /// - internal sealed class ApplicationEventsResolver : ManyObjectsResolverBase + /// + /// This is disposable because after the app has started it should be disposed to release any memory being occupied by instances. + /// + internal sealed class ApplicationEventsResolver : ManyObjectsResolverBase, IDisposable { private readonly LegacyStartupHandlerResolver _legacyResolver; @@ -53,7 +57,7 @@ namespace Umbraco.Core.ObjectResolution protected override bool SupportsClear { - get { return false; } + get { return false; } } protected override bool SupportsInsert @@ -61,7 +65,7 @@ namespace Umbraco.Core.ObjectResolution get { return false; } } - private class LegacyStartupHandlerResolver : ManyObjectsResolverBase + private class LegacyStartupHandlerResolver : ManyObjectsResolverBase, IDisposable { internal LegacyStartupHandlerResolver(IEnumerable legacyStartupHandlers) : base(legacyStartupHandlers) @@ -73,7 +77,72 @@ namespace Umbraco.Core.ObjectResolution { get { return Values; } } - } + public void Dispose() + { + Reset(); + } + } + + private bool _disposed; + private readonly ReaderWriterLockSlim _disposalLocker = new ReaderWriterLockSlim(); + + /// + /// Gets a value indicating whether this instance is disposed. + /// + /// + /// true if this instance is disposed; otherwise, false. + /// + public bool IsDisposed + { + get { return _disposed; } + } + + /// + /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources. + /// + /// 2 + public void Dispose() + { + Dispose(true); + + // Use SupressFinalize in case a subclass of this type implements a finalizer. + GC.SuppressFinalize(this); + } + + ~ApplicationEventsResolver() + { + // Run dispose but let the class know it was due to the finalizer running. + Dispose(false); + } + + private void Dispose(bool disposing) + { + // Only operate if we haven't already disposed + if (IsDisposed || disposing == false) return; + + using (new WriteLock(_disposalLocker)) + { + // Check again now we're inside the lock + if (IsDisposed) return; + + // Call to actually release resources. This method is only + // kept separate so that the entire disposal logic can be used as a VS snippet + DisposeResources(); + + // Indicate that the instance has been disposed. + _disposed = true; + } + } + + /// + /// Clear out all of the instances, we don't want them hanging around and cluttering up memory + /// + private void DisposeResources() + { + _legacyResolver.Dispose(); + Reset(); + } + } } \ No newline at end of file diff --git a/src/Umbraco.Core/ObjectResolution/ManyObjectsResolverBase.cs b/src/Umbraco.Core/ObjectResolution/ManyObjectsResolverBase.cs index 0edaf68243..c19ba000a0 100644 --- a/src/Umbraco.Core/ObjectResolution/ManyObjectsResolverBase.cs +++ b/src/Umbraco.Core/ObjectResolution/ManyObjectsResolverBase.cs @@ -322,7 +322,7 @@ namespace Umbraco.Core.ObjectResolution } /// - /// Clears the list of types. + /// Clears the list of types /// /// the resolver does not support clearing types. public virtual void Clear() @@ -336,6 +336,20 @@ namespace Umbraco.Core.ObjectResolution } } + /// + /// WARNING! Do not use this unless you know what you are doing, clear all types registered and instances + /// created. Typically only used if a resolver is no longer used in an application and memory is to be GC'd + /// + internal void Reset() + { + using (new WriteLock(_lock)) + { + _instanceTypes.Clear(); + _sortedValues = null; + _applicationInstances = null; + } + } + /// /// Inserts a type at the specified index. /// diff --git a/src/Umbraco.Core/Persistence/Migrations/Upgrades/TargetVersionSixTwoZero/AdditionalIndexesAndKeys.cs b/src/Umbraco.Core/Persistence/Migrations/Upgrades/TargetVersionSixTwoZero/AdditionalIndexesAndKeys.cs index e4d2496903..c4d3c1c572 100644 --- a/src/Umbraco.Core/Persistence/Migrations/Upgrades/TargetVersionSixTwoZero/AdditionalIndexesAndKeys.cs +++ b/src/Umbraco.Core/Persistence/Migrations/Upgrades/TargetVersionSixTwoZero/AdditionalIndexesAndKeys.cs @@ -8,10 +8,10 @@ namespace Umbraco.Core.Persistence.Migrations.Upgrades.TargetVersionSixTwoZero { public override void Up() { - Create.Index("IX_umbracoNodeTrashed").OnTable("umbracoNode").OnColumn("trashed").Ascending().WithOptions().NonClustered(); - Create.Index("IX_cmsContentVersion_ContentId").OnTable("cmsContentVersion").OnColumn("ContentId").Ascending().WithOptions().NonClustered(); - Create.Index("IX_cmsDocument_published").OnTable("cmsDocument").OnColumn("published").Ascending().WithOptions().NonClustered(); - Create.Index("IX_cmsDocument_newest").OnTable("cmsDocument").OnColumn("newest").Ascending().WithOptions().NonClustered(); + //Create.Index("IX_umbracoNodeTrashed").OnTable("umbracoNode").OnColumn("trashed").Ascending().WithOptions().NonClustered(); + //Create.Index("IX_cmsContentVersion_ContentId").OnTable("cmsContentVersion").OnColumn("ContentId").Ascending().WithOptions().NonClustered(); + //Create.Index("IX_cmsDocument_published").OnTable("cmsDocument").OnColumn("published").Ascending().WithOptions().NonClustered(); + //Create.Index("IX_cmsDocument_newest").OnTable("cmsDocument").OnColumn("newest").Ascending().WithOptions().NonClustered(); } public override void Down()