-
Notifications
You must be signed in to change notification settings - Fork 1.1k
Description
using Akka 1.2.0
If local actor system is created and disposed repeatedly then everything is fine.
If same is done with cluster actor system then there seems to be a memory leak after disposing.
Check tests:
-
IfLocalActorSystemIsStartedAndDisposedManyTimes_ThenThereShouldBeNoMemoryLeak
Output:
Got ActorIdentity: 42
After first run - MemoryUsage: 1mb
Iteration: 2 - MemoryUsage: 1mb
Got ActorIdentity: 42
Got ActorIdentity: 42
Iteration: 4 - MemoryUsage: 1mb
Got ActorIdentity: 42
Got ActorIdentity: 42
Iteration: 6 - MemoryUsage: 1mb
...
Got ActorIdentity: 42
Got ActorIdentity: 42
Iteration: 98 - MemoryUsage: 1mb
Got ActorIdentity: 42
Got ActorIdentity: 42
Iteration: 100 - MemoryUsage: 1mb
Got ActorIdentity: 42 -
IfClusterActorSystemIsCreatedAndDisposedManyTimes_ThenThereShouldBeNoMemoryLeak
Output:
Got ActorIdentity: 42
After first run - MemoryUsage: 35mb
Iteration: 2 - MemoryUsage: 35mb
Got ActorIdentity: 42
Got ActorIdentity: 42
Iteration: 4 - MemoryUsage: 102mb
Got ActorIdentity: 42
Got ActorIdentity: 42
Iteration: 6 - MemoryUsage: 169mb
System.InvalidOperationException : There seems to be a memory leak!
using System;
using Akka.Actor;
using Akka.Cluster.Tools.Client;
using Akka.Configuration;
using NUnit.Framework;
namespace StressTests
{
[TestFixture]
public class AkkaTests
{
private const string ClusterServerConfig = @"
akka {
actor {
provider = ""Akka.Cluster.ClusterActorRefProvider, Akka.Cluster""
}
remote {
helios.tcp {
hostname = ""127.0.0.1""
port = 3000
}
}
cluster {
seed-nodes = [""akka.tcp://ClusterServer@127.0.0.1:3000""]
}
}
";
private const string ClusterClientConfig = @"
akka {
actor {
provider = ""Akka.Cluster.ClusterActorRefProvider, Akka.Cluster""
}
remote {
helios.tcp {
hostname = ""127.0.0.1""
port = 3001
}
}
cluster {
client {
initial-contacts = [""akka.tcp://ClusterServer@127.0.0.1:3000/system/receptionist""]
}
}
}
";
[Test]
public void IfLocalActorSystemIsCreatedAndDisposedManyTimes_ThenThereShouldBeNoMemoryLeak()
{
TestForMemoryLeak(RunLocalSystem);
}
[Test]
public void IfClusterActorSystemIsCreatedAndDisposedManyTimes_ThenThereShouldBeNoMemoryLeak()
{
TestForMemoryLeak(RunClusterSystem);
}
private static void RunLocalSystem()
{
var system = ActorSystem.Create("Local");
var actor = system.ActorOf<TestActor>();
var result = actor.Ask<ActorIdentity>(new Identify(42)).Result;
TestContext.Progress.WriteLine("Got ActorIdentity: " + result.MessageId);
system.Terminate().Wait();
system.Dispose();
}
private void RunClusterSystem()
{
var serverAkkaConfig = ConfigurationFactory.ParseString(ClusterServerConfig);
var serverSystem = ActorSystem.Create("ClusterServer", serverAkkaConfig);
var serverActor = serverSystem.ActorOf<TestActor>("TestActor");
var receptionist = ClusterClientReceptionist.Get(serverSystem);
receptionist.RegisterService(serverActor);
var clientAkkaConfig = ConfigurationFactory.ParseString(ClusterClientConfig);
var clientSystem = ActorSystem.Create("ClusterClient", clientAkkaConfig);
var defaultConfig = ClusterClientReceptionist.DefaultConfig();
clientSystem.Settings.InjectTopLevelFallback(defaultConfig);
var clusterClientSettings = ClusterClientSettings.Create(clientSystem);
var clientActor = clientSystem.ActorOf(ClusterClient.Props(clusterClientSettings));
var result = clientActor.Ask<ActorIdentity>(new ClusterClient.Send("/user/TestActor",new Identify(42))).Result;
TestContext.Progress.WriteLine("Got ActorIdentity: " + result.MessageId);
clientSystem.Terminate().Wait();
serverSystem.Terminate().Wait();
clientSystem.Dispose();
serverSystem.Dispose();
}
private static void TestForMemoryLeak(Action action)
{
const int IterationCount = 100;
long memoryAfterFirstRun = 0;
for (var i = 1; i <= IterationCount; i++)
{
if (i % 2 == 0)
{
var currentMemory = GC.GetTotalMemory(true) / 1024 / 1024;
TestContext.Progress.WriteLine($"Iteration: {i} - MemoryUsage: {currentMemory}mb");
if (currentMemory > memoryAfterFirstRun + 100)
throw new InvalidOperationException("There seems to be a memory leak!");
}
action();
if (i == 1)
{
memoryAfterFirstRun = GC.GetTotalMemory(true) / 1024 / 1024;
TestContext.Progress.WriteLine($"After first run - MemoryUsage: {memoryAfterFirstRun}mb");
}
}
}
private class TestActor : ReceiveActor
{
}
}
}