Botframework-sdk: Bot memory leak in .Net SDK

Created on 21 Nov 2017  路  6Comments  路  Source: microsoft/botframework-sdk

Bot Info

  • SDK Platform: .NET
  • SDK Version: 3.11.0

Issue Description

Everytime u send a msg to the bot the memory usage stacks up but never gets down.
even when the client ends the session with the bot

In the picture u can see the diagnostic session from visual studio
the events around 1:10min are msgs the bot received from the client
botframework

Code Example

look at Step 1 from reproduction steps

Reproduction Steps

  1. use the visual studio template https://docs.microsoft.com/en-us/bot-framework/dotnet/bot-builder-dotnet-quickstart
  2. update to the newest BotBuilder SDK
  3. run the bot and send some msgs from the botframework-emulator

Expected Behavior

No Memory Leak

Actual Results

Memory Leak

Some additional information

im pretty new to the bot framework so i dont know if this a feature and memory gets cleaned after some hours or is this a real problem

bug investigate

Most helpful comment

This is not just a problem with local testing. It affects all .Net SDK bots.

The problem is in BotBuilder\CSharp\Library\Microsoft.Bot.Builder.Autofac\Fibers\DoNotSerializeResolver.cs:

IComponentRegistration registration;
if (registry.TryGetRegistration(service, out registration))
{
    // Autofac will still generate "implicit relationship types" (e.g. Func or IEnumerable)
    // and ignore the key in KeyedService
    bool generated = registry.IsRegistered(new KeyedService(new object(), serviceType));
    if (!generated)
    {
        value = this.context.ResolveComponent(registration, this.parameters);
        return true;
    }
}

The problem is that IsRegistered will create a new ServiceRegistrationInfo if it cannot find the KeyedService that is passed in. But the key for KeyedService is the new object(), which will never match any of the other keys (also new objects()).

Here's the source for IsRegistered, for reference:

// Autofac.Core.Registration.ComponentRegistry
private ServiceRegistrationInfo GetServiceInfo(Service service)
{
    ServiceRegistrationInfo result;
    if (this._serviceInfo.TryGetValue(service, ref result))  // This will never match so we don't hit the return
    {
        return result;
    }
    ServiceRegistrationInfo serviceRegistrationInfo = **new ServiceRegistrationInfo(service);**
    this._serviceInfo.Add(service, serviceRegistrationInfo);
    return serviceRegistrationInfo;
}

DoNotSerializeResolver was added in commit fdb443a3 to work around a bug in autofac about 6 months ago. The autofac issue is https://github.com/autofac/Autofac/issues/852.

All 6 comments

Hi @Wenish,

Thanks for your feedback. We will investigate if this could be a bug or a memory management issue.

Regards,
Francisco

Hi @Wenish

I tried to repro the issue. I do not see any memory leak as you've stated. See below attached screenshot.
I even sent many large text contents. The memory footprint stayed the same.

Have you got all your references updated as per prerequisites mentioned

image

@msmohan updated vs, every extension and created new project still same result

This is not just a problem with local testing. It affects all .Net SDK bots.

The problem is in BotBuilder\CSharp\Library\Microsoft.Bot.Builder.Autofac\Fibers\DoNotSerializeResolver.cs:

IComponentRegistration registration;
if (registry.TryGetRegistration(service, out registration))
{
    // Autofac will still generate "implicit relationship types" (e.g. Func or IEnumerable)
    // and ignore the key in KeyedService
    bool generated = registry.IsRegistered(new KeyedService(new object(), serviceType));
    if (!generated)
    {
        value = this.context.ResolveComponent(registration, this.parameters);
        return true;
    }
}

The problem is that IsRegistered will create a new ServiceRegistrationInfo if it cannot find the KeyedService that is passed in. But the key for KeyedService is the new object(), which will never match any of the other keys (also new objects()).

Here's the source for IsRegistered, for reference:

// Autofac.Core.Registration.ComponentRegistry
private ServiceRegistrationInfo GetServiceInfo(Service service)
{
    ServiceRegistrationInfo result;
    if (this._serviceInfo.TryGetValue(service, ref result))  // This will never match so we don't hit the return
    {
        return result;
    }
    ServiceRegistrationInfo serviceRegistrationInfo = **new ServiceRegistrationInfo(service);**
    this._serviceInfo.Add(service, serviceRegistrationInfo);
    return serviceRegistrationInfo;
}

DoNotSerializeResolver was added in commit fdb443a3 to work around a bug in autofac about 6 months ago. The autofac issue is https://github.com/autofac/Autofac/issues/852.

Not an Autofac bug but a desire to use Autofac in a way it wasn't intended (enumerate every registration in the container that has a particular key but an unknown type). I've responded in the autofac/Autofac#852 issue with some options on how to work around that, but there isn't an intent to add this sort of feature to Autofac (for reasons I mention in that issue).

Closing this issue.

The memory leak was fixed with this commit: https://github.com/Microsoft/BotBuilder/commit/992e29f4e0f61b98b31557fdba68d53fb8caabfc#diff-89fb66a1ea6d384cecdf910402faa180

Was this page helpful?
0 / 5 - 0 ratings

Related issues

maba4891 picture maba4891  路  3Comments

Arimov picture Arimov  路  3Comments

daveta picture daveta  路  3Comments

verdysh picture verdysh  路  3Comments

Vigneshramkumar picture Vigneshramkumar  路  3Comments