枚举 Autofac 生命周期跟踪的一次性用品

Enumerating disposables tracked by an Autofac lifetime

Autofac 使用生命周期范围作为处理在一个工作单元期间创建的所有组件的一种方式。虽然这是一个强大的功能,但很容易编写无法正确处理生命周期范围的代码,这会导致跟踪的一次性对象的数量随着时间的推移而增加:实际上是内存泄漏。

有没有一种方法可以在任何时间点监控 Lifetime Scope 跟踪的 Disposable 对象的数量。我有兴趣编写工具来帮助我找到与未将一次性用品正确分配给工作单元相关的问题。目前我使用内存分析器工具来查找泄漏,但这是一项非常繁重的工作。

我查看了 ILifetimeScope 的 public 界面,但没有看到任何有用的东西。

不幸的是,分析是 Autofac 目前的弱点之一。 There is a repository where some work was started on an analytics package 但肯定存在一些差距 - 例如,您可以跟踪一个对象何时 激活 并且您可以看到何时 lifetime scopes已处置,但您无法跟踪何时将单个 对象 作为范围的一部分处置。只是没有活动。

一个非常简单的激活跟踪模块如下所示:

using System;
using System.Collections.Generic;
using System.Linq;
using Autofac;
using Autofac.Core;

namespace DiagnosticDemo
{
  public class TrackingModule : Module
  {
    private readonly IDictionary<Type, int> _activations = new Dictionary<Type, int>();

    private readonly object _syncRoot = new object();

    public void WriteActivations()
    {
      foreach (var pair in this._activations.Where(p => p.Value > 0))
      {
        Console.WriteLine("* {0} = {1}", pair.Key, pair.Value);
      }
    }

    protected override void AttachToComponentRegistration(
      IComponentRegistry componentRegistry,
      IComponentRegistration registration)
    {
      if (registration.Ownership == InstanceOwnership.OwnedByLifetimeScope)
      {
        registration.Activated += this.OnRegistrationActivated;
      }
    }

    private void OnRegistrationActivated(
      object sender,
      ActivatedEventArgs<object> e)
    {
      if (e.Instance is IDisposable)
      {
        var type = e.Instance.GetType();
        Console.WriteLine("Activating {0}", type);
        lock (this._syncRoot)
        {
          if (this._activations.ContainsKey(type))
          {
            this._activations[type]++;
          }
          else
          {
            this._activations[type] = 1;
          }
        }
      }
    }
  }
}

你会像这样使用它:

static void Main(string[] args)
{
  var trackingModule = new TrackingModule();

  var builder = new ContainerBuilder();
  // Register types, then register the module
  builder.RegisterType<Consumer>().As<IConsumer>();
  builder.RegisterType<DisposableDependency>().As<IDependency>();
  builder.RegisterType<NonDisposableDependency>().As<IDependency>();
  builder.RegisterModule(trackingModule);
  var container = builder.Build();

  // Do whatever it is you want to do...
  using (var scope = container.BeginLifetimeScope())
  {
    scope.Resolve<IConsumer>();
  }

  // Dump data
  Console.WriteLine("Activation totals:");
  trackingModule.WriteActivations();
}

但是,这不会告诉您哪些项目没有 处理,我想这正是您想知道的。不过,它可能会给你一些想法,或者至少有一点帮助。

如果您有兴趣帮助改进 Autofac 中的分析,我们很乐意 take PRs or specific design ideas for how to improve

Whitebox is a working but un-finished GUI diagnostics tool for Autofac that does pretty much what you're looking for. It may need an update for the latest version of Autofac - any help with getting the project back up and running would be welcome. Some docs on the old Google Code page.