2016-12-19 5 views
2

Windows 서비스에서 Autofac for Ninject를 드롭 인으로 대체하려고 시도 중입니다. (잠재적으로 Autofac 기능을 보완하기 위해 개선하기 전에) 메모리로 실행 중입니다. 발행물. 여기 Autofac이 설치된 Windows 서비스가 참조로 고정

는 우리의 문제를 재현하지 않는 인위적인 예,하지만 응용 프로그램의 현재 레이아웃을 보여줍니다 기본적으로

class Program 
    { 
     static void Main(string[] args) 
     { 
      ContainerBuilder builder = new ContainerBuilder(); 

      var ms = new MemoryStream(new byte[10000000]); 
      var ms2 = new MemoryStream(new byte[10000000]); 

      builder.RegisterType<BaseRepo>() 
       .WithParameter("ms", ms) 
       .As<IBaseRepo>(); 

      builder.RegisterType<DerivedRepo>() 
       .WithParameter("ms", ms2) 
       .As<IDerivedRepo>(); 

      builder.RegisterType<BaseFactory>().As<IBaseFactory>(); 
      builder.RegisterType<Derived>().AsSelf(); 
      builder.RegisterType<Derived>().Keyed<Base>(BaseEnum.Derived).As<Base>(); 

      var container = builder.Build(); 

      var factory = container.Resolve<IBaseFactory>(); 

      while (true) 
      { 
       var instance = factory.Create(BaseEnum.Derived); 
       instance.DoSomething(); 
       instance.Dispose(); 
       Thread.Sleep(5000); 
      } 
     } 
    } 

    public interface IDerivedRepo : IDisposable {} 

    public class DerivedRepo : IDerivedRepo 
    { 
     private readonly MemoryStream _ms; 

     public DerivedRepo(MemoryStream ms) 
     { 
      _ms = ms; 
     } 

     public void Dispose() 
     { 
      _ms.Dispose(); 
     } 
    } 

    public interface IBaseRepo : IDisposable {} 

    public class BaseRepo : IBaseRepo 
    { 
     private readonly MemoryStream _ms; 

     public BaseRepo(MemoryStream ms) 
     { 
      _ms = ms; 
     } 

     public void Dispose() 
     { 
      _ms.Dispose(); 
     } 
    } 

    public enum BaseEnum 
    { 
     Derived = 1 
    } 

    public interface IBaseFactory 
    { 
     Base Create(BaseEnum baseEnum); 
    } 

    public class BaseFactory : IBaseFactory 
    { 
     private readonly IComponentContext _componentContext; 

     public BaseFactory(IComponentContext componentContext) 
     { 
      _componentContext = componentContext; 
     } 

     public Base Create(BaseEnum baseEnum) 
     { 
      return _componentContext.ResolveOptionalKeyed<Base>(baseEnum); 
     } 
    } 

    public interface IDisposableThing : IDisposable 
    { 
     void DoSomething(); 
    } 

    public abstract class Base : IDisposableThing 
    { 
     protected readonly IBaseRepo BaseRepo; 

     protected Base(IBaseRepo baseRepo) 
     { 
      BaseRepo = baseRepo; 
     } 

     public void Dispose() 
     { 
      Console.WriteLine("Disposing base"); 
      BaseRepo.Dispose(); 
     } 

     public abstract void DisposeChildren(); 

     public void DoSomething() 
     { 
      Console.WriteLine("Doing something"); 
     } 
    } 

    public class Derived : Base 
    { 
     private readonly IDerivedRepo _derivedRepo; 

     public Derived(IBaseRepo baseRepo, IDerivedRepo derivedRepo) : base(baseRepo) 
     { 
      _derivedRepo = derivedRepo; 
     } 

     public override void DisposeChildren() 
     { 
      Console.WriteLine("Disposing derived"); 
      _derivedRepo.Dispose(); 
     } 
    } 

를, 우리 - 일정한 간격으로 -의 인스턴스를 인스턴스화하는 공장을 사용 열거 형 값을 기반으로하는 추상 클래스는 해당 인스턴스에서 일부 작업을 수행 한 다음 처리합니다. 문제는 해당 인스턴스가 가비지 수집기에 의해 정리되지 않고 응용 프로그램의 메모리 사용이 꾸준히 증가한다는 것입니다. DebugDiag2는 우리의 repos에있는 MemoryStream 구성원에 해당하는 인스턴스를 보유하고 있다고보고합니다 (실제 응용 프로그램에서는, 이들은 엔티티 프레임 워크 DBContext에 대한 래퍼입니다. 다른 코드는 분석에서보고되지 않으므로 계속 진행할 것이 없습니다.

확실한 대답을 내놓기에 충분하지 않다는 것을 알고 있습니다. 내가 더 찾고있는 것은 분명히 뭔가 잘못하고있는 부분에 대한 제안입니다. (전체 팀은 Autofac에 익숙하지 않습니다. 서비스 로케이터 방지 패턴,하지만 나는 그것이 우리가보고있는 문제를 일으키지 않는 것으로 가정).

답변

1

Autofac은 평생 범위 내에서 해결되는 개체를 추적하므로 정상적인 동작입니다. 관련 수명 범위가 자체 폐기 될 때 폐기됩니다. 귀하의 경우에는 중 하나만이며, 이는 빌더에서 컨테이너를 빌드 할 때 생성 된 것입니다.

평생 범위가 작동하는 방식에 대해 자세히 설명하는 this documentation page을 읽어 보시기 바랍니다.

일정한 간격 내에서 새 작업을 시작할 때마다 내부 수명 범위를 만드는 것이 출발점입니다. 다음과 같이 표시 될 수 있습니다.

var container = builder.Build(); 

while (true) 
{ 
    // Create an inner lifetime scope that will keep track of every 
    // object it creates 
    using (var lifetimeScope = container.BeginLifetimeScope()) 
    { 
     // resolve objects from `lifetimeScope` 
     // do work with them 
    } 
    // At the end of the using directive, lifetimeScope will be disposed 
    // and will dispose with it any objects it kept track of 

    Thread.Sleep(5000); 
}