diff --git a/src/core/Akka.Streams/ActorMaterializer.cs b/src/core/Akka.Streams/ActorMaterializer.cs
index b71e1f05938..e4212faa6e8 100644
--- a/src/core/Akka.Streams/ActorMaterializer.cs
+++ b/src/core/Akka.Streams/ActorMaterializer.cs
@@ -6,7 +6,9 @@
//-----------------------------------------------------------------------
using System;
+using System.Collections.Concurrent;
using System.Runtime.Serialization;
+using System.Threading.Tasks;
using Akka.Actor;
using Akka.Configuration;
using Akka.Dispatch;
@@ -43,6 +45,18 @@ public static Config DefaultConfig()
#region static
+ ///
+ /// Injecting the top-level Materializer HOCON configuration over and over again is expensive, so we want to avoid
+ /// doing it each time a materializer is instantiated. This flag will be set to true once the configuration has been
+ /// injected the first time.
+ ///
+ private static readonly ConcurrentDictionary InjectedConfig = new();
+
+ ///
+ /// Cache the default materializer settings so we don't constantly parse them
+ ///
+ private static readonly ConcurrentDictionary DefaultSettings = new();
+
///
///
/// Creates a ActorMaterializer which will execute every step of a transformation
@@ -75,9 +89,28 @@ public static ActorMaterializer Create(IActorRefFactory context, ActorMaterializ
var haveShutDown = new AtomicBoolean();
var system = ActorSystemOf(context);
- system.Settings.InjectTopLevelFallback(DefaultConfig());
+ if(!InjectedConfig.TryGetValue(system, out _) && InjectedConfig.TryAdd(system, true))
+ {
+ // Inject the top-level fallback config for the Materializer once, and only once.
+ // This is a performance optimization to avoid having to do this on every materialization.
+ system.Settings.InjectTopLevelFallback(DefaultConfig());
- settings = settings ?? ActorMaterializerSettings.Create(system);
+ static async Task CleanUp(ActorSystem sys)
+ {
+ // remove ActorSystem from cache when it terminates so we don't leak memory
+ await sys.WhenTerminated.ConfigureAwait(false);
+ InjectedConfig.TryRemove(sys, out _);
+ DefaultSettings.TryRemove(sys, out _);
+ }
+
+#pragma warning disable CS4014
+ CleanUp(system);
+#pragma warning restore CS4014
+
+ }
+
+ // use the default settings if none have been passed in
+ settings ??= DefaultSettings.GetOrAdd(system, ActorMaterializerSettings.Create);
return new ActorMaterializerImpl(
system: system,
@@ -90,14 +123,14 @@ public static ActorMaterializer Create(IActorRefFactory context, ActorMaterializ
private static ActorSystem ActorSystemOf(IActorRefFactory context)
{
- if (context is ExtendedActorSystem)
- return (ActorSystem)context;
- if (context is IActorContext)
- return ((IActorContext)context).System;
- if (context == null)
- throw new ArgumentNullException(nameof(context), "IActorRefFactory must be defined");
-
- throw new ArgumentException($"ActorRefFactory context must be a ActorSystem or ActorContext, got [{context.GetType()}]");
+ return context switch
+ {
+ ExtendedActorSystem system => system,
+ IActorContext actorContext => actorContext.System,
+ null => throw new ArgumentNullException(nameof(context), "IActorRefFactory must be defined"),
+ _ => throw new ArgumentException(
+ $"ActorRefFactory context must be a ActorSystem or ActorContext, got [{context.GetType()}]")
+ };
}
#endregion