2013-10-24 13 views
1

我努力理解在我的内存泄漏的来源。我在研究过程中遇到了post的修改版本。我们使用StructureMap,我们要使用AOP的MiniProfiler所以这似乎是一个完美的东西去尝试,但是当我实现它,我开始获得海量内存泄漏。我追踪了泄漏点,并创建了代理服务器。如果我保留所有其他代码相同,只需删除.EnrichWith(...)调用,内存泄漏就会消失。我创建代理类的引导程序类,像这样:使用CastleMap动态代理的StructureMap时是否存在内存泄漏?

x.For<IServiceInterface>() 
.Use<ServiceClass>() 
.EnrichWith(ex => DynamicProxyHelper. 
    CreateInterfaceProxyWithTargetInterface(typeof(IServiceInterface), ex)); 

动态代理助手类:

public class DynamicProxyHelper 
{ 
    public static IEnumerable<Type> GetScannableTypes() 
    { 
     var types = Assembly.GetExecutingAssembly().GetTypes(); 
     var scannableTypes = new List<Type>(); 
     foreach (var type in types) 
     { 
      // http://www.hanselman.com/blog/DoesATypeImplementAnInterface.aspx 
      if (typeof (IAttributeScanTask).IsAssignableFrom(type) 
       && type.FullName != typeof (IAttributeScanTask).FullName) 
      { 
       scannableTypes.Add(type); 
      } 
     } 

     return scannableTypes; 
    } 

    public static object CreateInterfaceProxyWithTargetInterface<T>(Type interfaceType, T obj) 
    { 
     if (!interfaceType.IsInstanceOfType(obj)) 
     { 
      throw new ArgumentException(
       "DynamicProxyHelper: Object passed to the proxy must inherit from the interface type passed to the proxy."); 
     } 

     // Create the proxy and return the result 
     var dynamicProxy = new ProxyGenerator(); 
     var scannableTypes = GetScannableTypes(); 

     var result = dynamicProxy.CreateInterfaceProxyWithTargetInterface(
      interfaceType, 
      obj, 
      new IInterceptor[] { new MyInterceptor(obj.GetType(), new AttributeScanEngine(), scannableTypes)}); 

     return result; 
    } 
} 

而且MyInterceptor类:

public interface IMyInterceptor : IInterceptor {} 
public class MyInterceptor : IMyInterceptor 
{ 
    private readonly Type _concreteType; 
    private readonly IAttributeScanEngine _scanEngine; 
    private readonly IEnumerable<Type> _scannableTypes; 
    private const string AttributeNameSpace = "MyAttributes"; 


    public MyInterceptor() : this(typeof(object), new AttributeScanEngine(), new List<Type>()){} 

    public MyInterceptor(Type concreteType, IAttributeScanEngine scanEngine, IEnumerable<Type> scannableTypes) 
    { 
     _concreteType = concreteType; 
     _scanEngine = scanEngine; 
     _scannableTypes = scannableTypes; 
    } 

    public void Intercept(IInvocation invocation) 
    { 
     var scanType = ResolveScanType(invocation); 

     // We found a matching attribute that can be applied 
     if (scanType != null) 
     { 
      // execute the custom task we need to run 
      _scanEngine.Run(invocation, scanType, _concreteType); 
     } 
     else 
     { 
      // no scanned types could be found so execute the method as is 
      invocation.Proceed(); 
     } 

    } 

    protected internal virtual Type ResolveScanType(IInvocation invocation) 
    { 
     foreach (var type in _scannableTypes) 
     { 
      var attributeName = GetAttributeName(type.Name); 
      var attributeType = Type.GetType(attributeName); 
      if (attributeType != null) 
      { 
       var attributeDecoration = Attribute.GetCustomAttribute(invocation.GetConcreteMethodInvocationTarget(), attributeType, true); 

       // We found an attribute for this scan type 
       if (attributeDecoration != null) 
       { 
        return type; 
       } 
      } 
     } 

     return null; 
    } 

    protected internal virtual string GetAttributeName(string typeName) 
    { 
     var aspectName = typeName.Substring(0, typeName.IndexOf("ScanTask")); 
     return AttributeNameSpace + "." + aspectName + "Attribute"; 
    }   
} 

我相信这是关系到通过调用EnrichWith代理的创建,因为如果我离开的代码的其他部分一样,只是删除通话,内存泄漏消失。我在这里做错了什么?

回答

0

我使用Structuremap和Castle.Proxy为好,但有点不同的方式。所以,虽然这不是内存泄漏问题的直接答案,但它可能会给你另一种看法。

背后的想法就是,而不是返回请求的对象,我们将返回承诺,一个wrapper对象。另外,我们正在使用setter注入,这确实证明了不仅构造函数注入是有效的概念。首先,存在Structuremap调用自定义的公约对象的配置:

x.Scan(s => 
{ 
    s.Convention<ProxyConvention>(); 
    s.WithDefaultConventions(); 
} 
.. 
x.SetAllProperties(.. // configure setter injeciton 

的代理公约,确实注入包装,作为实现:

[CLSCompliant(false)] 
public class ProxyConvention : DefaultConventionScanner 
{ 
    public override void Process(Type type, Registry registry) 
    { 
     var interfacesToHandle = type.GetInterfaces() 
      .Where(i => i... // select what which interface should be mapped 

     foreach (var inter in interfacesToHandle) 
     { 
      var setting = registry 
       .For(inter) 
       .HybridHttpOrThreadLocalScoped(); 
       .Use(new ProxyInstance(type)); // here we go to inject wrapper 
    ... 

所以,现在,我们已经注入使用ProxInstance对象实现我们的接口。还有就是内容:

public ProxyInstance(Type type) 
{ 
    ConcreteType = type; // the type for our Wrapper, the real implementation 
} 
protected override object build(Type pluginType, BuildSession session) 
{ 
    var aopFilters = 
     // my custom way how to inject more AOP filters 
     AopFilterManager.GetFilters() 
     // the core for us, one of the interceptors is our Wrapper 
     .Union(new[] { new Wrapper(ConcreteType) }) 
     .ToArray(); 

    // Castle will emit a proxy for us, but the Wrapper will do the job 
    var proxy = Factory 
     .CreateClassProxy(ConcreteType, AopFilterManager.AopOptions, aopFilters); 

    return proxy; 
} 

我们可以看到,在这一刻,我们已经创建了一个Proxy与城堡,与Interceptors丰富它。 Wrapper对象负责实例化真实对象,仅在第一次触摸它的时刻。因此,循环引用是不是一个问题,其实他们是欢迎:

public class Wrapper : IInterceptor 
{ 
    object _lazy; 
    protected readonly Type Type; 

    public Wrapper(Type type) 
    { 
     Type = type; 
    } 

    public void Intercept(IInvocation invocation) 
    { 
     if (_lazy.IsNull()) // lazily instantiate the instance 
     { 
      _lazy = ObjectFactory.GetInstance(Type); 
     } 
     try 
     { 
      var method = invocation.Method; 
      if (method.ContainsGenericParameters) 
      { 
       method = method.MakeGenericMethod(invocation.GenericArguments); 
      } 
      invocation.ReturnValue = method.Invoke(_lazy, invocation.Arguments); 
     } 
     catch (TargetInvocationException ex) 
     { 
      // PublishingManager.Publish(.... // publish exception 
      throw; 
     } 
    } 
} 

我类似的答案可以在这里找到StructureMap - Circular Dependencies and Lazy Initialization of Setter Properties
(没有为VS 2012 Catharsis guidance,创建解决方案,在这里你可以看到它在行动)

+0

谢谢您的回答,有一些很有趣的东西来工作,通过。我会尝试修改我们封装类的方式来模拟你的做法,看看是否还有内存泄漏。 – akousmata

3

如果你看看这个similar issue你可以看到他们主张使用单例实例,以便它重用动态生成的类型。内部的,而不是newing它每次DynamicProxyHelper尝试添加private static readonly ProxyGenerator dynamicProxy = new ProxyGenerator();和参考。

+0

谢谢你的回答,不幸的是,这个项目被搁置了,直到晚些时候,我还没有得到时间来处理它。您提供的链接内容丰富,如果我可以抽出时间查看,我会回过头来回答这个问题并标记为答案。 – akousmata