Azure / DotNetty

DotNetty project – a port of netty, event-driven asynchronous network application framework
Other
4.09k stars 977 forks source link

TlsHandler memory #246

Open agnauck opened 7 years ago

agnauck commented 7 years ago

When I connect and disconnect a socket several times the memory always goes up. According to the VS profiler it comes from the TlsHandler MediationStream, SslStreamInternal, SslStream.

Is it possible that there is a memory leak? Or is there something specific I need to call on the TlsHandler when I disconnect and reconnect? Tried to remove the handler and call Dispose on it. But this did not help.

PeterTruchly commented 7 years ago

Did You try to observe this for longer period of time? I found out (in my case) that client connections are left open for 30s after being closed by application. https://github.com/Azure/DotNetty/issues/238

agnauck commented 7 years ago

no I haven't. I just wrote a loop which opens and coses a connection 500 times in a row. Will try to wait some time and call the GC to see it makes a difference

nayato commented 7 years ago

@agnauck I'd suggest repeating the scenario a few hundred times, then forcing GC and checking the profile afterwards. Tip: you can call GC on running app from PerfView.

nayato commented 7 years ago

@agnauck any update on this?

agnauck commented 7 years ago

sorry for the delay.

I have modified the SecureChat.Client example to reproduce. There is a loop for opening and closing the connection many times.

Also attached a screenshot of the memory dump which shows the reference count which matches exatcly the number of connections. And those references don't get GC collected.

dotnetty-tls-memory-dump

namespace SecureChat.Client
{
    using System;
    using System.IO;
    using System.Net;
    using System.Net.Security;
    using System.Security.Cryptography.X509Certificates;
    using System.Threading.Tasks;
    using DotNetty.Codecs;
    using DotNetty.Handlers.Tls;
    using DotNetty.Transport.Bootstrapping;
    using DotNetty.Transport.Channels;
    using DotNetty.Transport.Channels.Sockets;
    using Examples.Common;
    using System.Threading;

    class Program
    {
        static async Task RunClientAsync()
        {
            ExampleHelper.SetConsoleLogger();

            var group = new MultithreadEventLoopGroup();

            X509Certificate2 cert = null;
            string targetHost = null;
            if (ClientSettings.IsSsl)
            {
                cert = new X509Certificate2(Path.Combine(ExampleHelper.ProcessDirectory, "dotnetty.com.pfx"), "password");
                targetHost = cert.GetNameInfo(X509NameType.DnsName, false);
            }
            try
            {
                var bootstrap = new Bootstrap();
                bootstrap
                    .Group(group)
                    .Channel<TcpSocketChannel>()
                    .Option(ChannelOption.TcpNodelay, true)
                    .Handler(new ActionChannelInitializer<ISocketChannel>(channel =>
                    {
                        IChannelPipeline pipeline = channel.Pipeline;

                        if (cert != null)
                        {
                            pipeline.AddLast(new TlsHandler(stream => new SslStream(stream, true, (sender, certificate, chain, errors) => true), new ClientTlsSettings(targetHost)));
                        }

                        pipeline.AddLast(new DelimiterBasedFrameDecoder(8192, Delimiters.LineDelimiter()));
                        pipeline.AddLast(new StringEncoder(), new StringDecoder(), new SecureChatClientHandler());
                    }));

                for (int i = 0; i < 2000; i++)
                {
                    IChannel bootstrapChannel = await bootstrap.ConnectAsync(new IPEndPoint(ClientSettings.Host, ClientSettings.Port));
                    Thread.Sleep(100);
                    await bootstrapChannel.WriteAndFlushAsync("Hello World" + "\r\n");
                    Thread.Sleep(100);
                    await bootstrapChannel.CloseAsync();                 
                }
                Console.ReadLine();                
            }
            finally
            {
                group.ShutdownGracefullyAsync().Wait(1000);
            }
        }

        static void Main() => RunClientAsync().Wait();
    }
}
baywet commented 6 years ago

running into the same issue, have you found a solution? (using iot hub sdk)

yj1118 commented 6 years ago

running into the same issue

TailyFair commented 3 years ago

Any updates on this issue?

PeterTruchly commented 3 years ago

Any updates on this issue?

There is an additional explanation on what is (probably) causing this issue here: #239 Technically it waits the maximum timeout to shutdown that connection gracefully, only solution is to shorten that timeout when closing connection.