castleproject / Core

Castle Core, including Castle DynamicProxy, Logging Services and DictionaryAdapter
http://www.castleproject.org/
Other
2.2k stars 467 forks source link

ProxyGenerator leaking #675

Closed kdma closed 2 weeks ago

kdma commented 8 months ago

Hi we have a Service Fabic cluster and we use Castle.Core.AsyncInterceptor (2.0.0 which has dependency towards Castle.Core 4.4.0) for telemetry injection, we noticed DynamicProxyGenAssembly2 modules leaking.

This is the setup for classes and DI:

public class ServiceInstanceGenerator
    {
        private readonly LoggingInterceptor _loggingInterceptor;
        private readonly ProxyGenerator _proxyGenerator;

        public ServiceInstanceGenerator(LoggingInterceptor loggingInterceptor, ProxyGenerator proxyGenerator)
        {
            _loggingInterceptor = loggingInterceptor;
            _proxyGenerator = proxyGenerator;
        }

        public TInterface GetActor<TInterface>(ActorId id) where TInterface : class, IActor
        {
            var service = ActorProxy.Create<TInterface>(id);
            return _proxyGenerator.CreateInterfaceProxyWithTargetInterface(service, _loggingInterceptor);
        }
        public TInterface GetService<TInterface>(Uri uri) where TInterface : class, IService
        {
            var service = ServiceProxy.Create<TInterface>(uri);
            return _proxyGenerator.CreateInterfaceProxyWithTargetInterface(service, _loggingInterceptor);
        }
    }
internal class ContainerModule : Module
    {

        protected override void Load(ContainerBuilder builder)
        {
            builder.RegisterType<ProxyGenerator>().AsSelf().SingleInstance();
            builder.RegisterInstance(new JsonSerializerOptions() { Converters = { new ByteArrayConverter() } });
            builder.RegisterType<LoggingInterceptor>().AsSelf().SingleInstance();
            builder.RegisterType<ServiceInstanceGenerator>().AsSelf().SingleInstance();
            builder.RegisterType<AssignmentsActor>().AsSelf().SingleInstance();
            builder.RegisterType<TelemetryClient>().AsSelf().SingleInstance();
            builder.Register((c, p) => c.Resolve<ServiceInstanceGenerator>().GetActor<ITransactions>(p.TypedAs<ActorId>())).As<ITransactions>();
        }

    }
 public class AssignmentsActor
 {
     private readonly Func<ActorId, ITransactions> _actorFactory;

     public AssignmentsActor(Func<ActorId, ITransactions> actorFactory)
     {
         _actorFactory = actorFactory;
     }

private ITransactions GetActor(ActorId id)
{
    return _actorFactory(id);
}

We tought that by registering the dependencies as single istance and the factory we could prevent the DynamicProxyGenLeaking but with this setup we can find this in the dumps:

image

Is our reasoning correct?

stakx commented 8 months ago

This appears to be more of an issue with your DI container than with DynamicProxy per se. Perhaps .SingleInstance() doesn't do what you think it does? (For example, it might create a single instance per web request or something like that.) Either way, I'm afraid you might be at the wrong repository here.

kdma commented 8 months ago

Hi stakx, Thanks I believe its something in between Autofac and Castle and of course SF the mother of all the beasts not playing nicely with each other. I am going to crosspost there as suggested and update here for anyone wandering in the future. :)

stakx commented 2 weeks ago

@kdma, I am closing this (by now pretty stale) issue, as I still don't see how this problem could be solved on DynamicProxy's side (which is what this repo is for). Our guidance is clear: you're encouraged to reuse ProxyGenerator instances in order to benefit from proxy type caching (see the documentation). Since in your case it is Autofac that instantiates the ProxyGenerator instance(s), and it's perhaps Service Fabric that controls the Autofac container(s) lifetime(s), I think you'd need to solve the problem there.