2012-12-05 3 views
0

컨테이너가 응용 프로그램 기간 동안 DerivedTypeConstructorSelectorPolicy의 인스턴스를 보유하는 문제가 발생했습니다. TypeInterceptionStrategy의 다음 두 줄의 코드가 이전 정책을 새 정책으로 래핑하고 두 인스턴스 (또는 그 이상, 인터셉트 된 클래스의 Resolve를 호출 할 때마다 유지됨)에 대한 기존 정책을 래핑하지 않는다면 그렇게 나쁘지 않을 것입니다. 문제가 복잡해질 것입니다.) .NET Memory Profiler를 실행할 때이를 볼 수 있습니다. 당신이 수업을 많이 차단되어 있고 다음 GC가 회수 할 수없는 메모리에 구멍을 얻을 때 Microsoft Unity - DerivedTypeConstructorSelectorPolicy 메모리 누수

IConstructorSelectorPolicy originalConstructorSelectorPolicy = PolicyListExtensions.Get<IConstructorSelectorPolicy>(context.Policies, (object) context.BuildKey, out containingPolicyList); 
PolicyListExtensions.Set<IConstructorSelectorPolicy>(containingPolicyList, (IConstructorSelectorPolicy) new TypeInterceptionStrategy.DerivedTypeConstructorSelectorPolicy(proxyType, originalConstructorSelectorPolicy), (object) context.BuildKey); 

정책이 스레드 안전을 보장하기 위해 복사됩니다 특히 한, 2 세대 수집의 대패의 원인이됩니다. 정책 목록에 충분한 수의 항목이 있으면 LOH로 이동하게되어 스레 싱을 더욱 악화시킵니다.

우리 응용 프로그램이 Integrated Pipeline과 32 비트 모드가 아닌 IIS Classic에서 실행된다는 사실에주의해야합니다. 이중 whammy입니다. 64 비트 모드에서 더 많은 공간을 할당 할 수 있다면 그렇게 나쁘지 않을 것입니다. 그러나 여전히 우리는 IIS가 제공 한 가상 메모리에 매료되어 있습니다. GC가 추가 메모리를 할당하고 요청이 죽기 시작하기에 충분한 공간을 GC가 찾지 못해 빠르게 진행됩니다.

파일에는 3 개의 수정본 만 있으며, 원본 수정본에는이 문제가없는 것처럼 보입니다. 다른 사람이이 문제를 겪었습니까? 아니면이 동작을 설명하는 내용이 누락 되었습니까?

이이 페이스트 빈에 게시 설명하는 매우 간단한 프로그램에 대한 링크 : http://pastebin.com/DYG3GXNm

.NET 메모리 프로파일 (또는 선택의 프로파일 러)를 사용하고 DerivedTypeConstructorSelectorPolicy에 대한보고는, 당신은 각 반복을 통해 성장하는 것을 지켜보고 있습니다 그것이 커질수록 originalConstructorSelectorPolicy가 긴 체인의 이전 인스턴스를 계속 참조하는지 확인하고 확인할 수 있습니다.

우리가 가로 채는 클래스 수의 예로는 약 1300 건 정도의 등록이 있습니다.

+0

또한 사용 된 LifetimeManager가 내 테스트와 다른 점이없는 것 같습니다. – Mike

답변

1

그동안 해결책을 찾았습니다. 간단한 수정이지만 Interception 및 TypeInterceptionStrategy를 재정의해야합니다. 수정본은 정책 목록에서 어떤 유형이 나오는지 확인하는 일회성 평가 도구였습니다.

이것은 TypeInterceptionStrategy에서 코드입니다 : 물론

if (originalConstructorSelectorPolicy is DefaultUnityConstructorSelectorPolicy) 
{ 
    containingPolicyList.Set<IConstructorSelectorPolicy>(new CustomDerivedTypeConstructorSelectorPolicy(proxyType, originalConstructorSelectorPolicy), context.BuildKey); 
} 

, 그것을, 당신은 TypeInterceptionStrategy를 복사하고 그냥 수정으로 수행 같은 일을 할 수있는 변경하기 위해, 그것은 될 수 없습니다 PreBuildUp 메소드를 오버라이드 (override)하여 간단하게 수정되었습니다.

다른 사람들이 문제에 부딪 힐 경우를 대비하여 여기에서 전체 픽스를 붙여 넣습니다.

public class CustomTypeInterceptionStrategy : BuilderStrategy 
{ 
    public override void PreBuildUp(IBuilderContext context) 
    { 
     Guard.ArgumentNotNull(context, "context"); 

     if (context.Existing != null) 
     { 
      return; 
     } 

     Type type = context.BuildKey.Type; 
     ITypeInterceptionPolicy typePolicy = FindInterceptionPolicy<ITypeInterceptionPolicy>(context); 

     if (typePolicy == null) 
     { 
      return; 
     } 

     ITypeInterceptor interceptor = typePolicy.GetInterceptor(context); 

     if (!interceptor.CanIntercept(type)) 
     { 
      return; 
     } 

     IInterceptionBehaviorsPolicy behaviorPolicy = FindInterceptionPolicy<IInterceptionBehaviorsPolicy>(context); 

     IEnumerable<IInterceptionBehavior> interceptionBehaviors = behaviorPolicy == null 
                     ? Enumerable.Empty<IInterceptionBehavior>() 
                     : behaviorPolicy.GetEffectiveBehaviors(context, interceptor, type, type).Where(ib => ib.WillExecute); 

     IAdditionalInterfacesPolicy interceptionPolicy3 = FindInterceptionPolicy<IAdditionalInterfacesPolicy>(context); 
     IEnumerable<Type> additionalInterfaces1 = interceptionPolicy3 != null ? interceptionPolicy3.AdditionalInterfaces : Type.EmptyTypes; 
     context.Policies.Set(new CustomEffectiveInterceptionBehaviorsPolicy() { Behaviors = interceptionBehaviors }, context.BuildKey); 

     Type[] additionalInterfaces2 = Intercept.GetAllAdditionalInterfaces(interceptionBehaviors, additionalInterfaces1); 
     Type proxyType = interceptor.CreateProxyType(type, additionalInterfaces2); 

     IPolicyList containingPolicyList; 
     IConstructorSelectorPolicy originalConstructorSelectorPolicy = context.Policies.Get<IConstructorSelectorPolicy>(context.BuildKey, out containingPolicyList); 

     if (originalConstructorSelectorPolicy is DefaultUnityConstructorSelectorPolicy) 
     { 
      containingPolicyList.Set<IConstructorSelectorPolicy>(new CustomDerivedTypeConstructorSelectorPolicy(proxyType, originalConstructorSelectorPolicy), context.BuildKey); 
     } 
    } 

    public override void PostBuildUp(IBuilderContext context) 
    { 
     Guard.ArgumentNotNull(context, "context"); 

     IInterceptingProxy interceptingProxy = context.Existing as IInterceptingProxy; 

     if (interceptingProxy == null) 
     { 
      return; 
     } 

     CustomEffectiveInterceptionBehaviorsPolicy interceptionBehaviorsPolicy = context.Policies.Get<CustomEffectiveInterceptionBehaviorsPolicy>(context.BuildKey, true); 

     if (interceptionBehaviorsPolicy == null) 
     { 
      return; 
     } 

     foreach (IInterceptionBehavior interceptor in interceptionBehaviorsPolicy.Behaviors) 
     { 
      interceptingProxy.AddInterceptionBehavior(interceptor); 
     } 
    } 

    private static TPolicy FindInterceptionPolicy<TPolicy>(IBuilderContext context) where TPolicy : class, IBuilderPolicy 
    { 
     TPolicy policy = context.Policies.Get<TPolicy>(context.BuildKey, false); 

     if (policy != null) 
     { 
      return policy; 
     } 

     return context.Policies.Get<TPolicy>(context.BuildKey.Type, false); 
    } 

    private class CustomEffectiveInterceptionBehaviorsPolicy : IBuilderPolicy 
    { 
     public CustomEffectiveInterceptionBehaviorsPolicy() 
     { 
      this.Behaviors = new List<IInterceptionBehavior>(); 
     } 

     public IEnumerable<IInterceptionBehavior> Behaviors { get; set; } 
    } 

    private class CustomDerivedTypeConstructorSelectorPolicy : IConstructorSelectorPolicy 
    { 
     private readonly Type interceptingType; 
     private readonly IConstructorSelectorPolicy originalConstructorSelectorPolicy; 

     public CustomDerivedTypeConstructorSelectorPolicy(Type interceptingType, IConstructorSelectorPolicy originalConstructorSelectorPolicy) 
     { 
      this.interceptingType = interceptingType; 
      this.originalConstructorSelectorPolicy = originalConstructorSelectorPolicy; 
     } 

     public SelectedConstructor SelectConstructor(IBuilderContext context, IPolicyList resolverPolicyDestination) 
     { 
      return FindNewConstructor(this.originalConstructorSelectorPolicy.SelectConstructor(context, resolverPolicyDestination), this.interceptingType); 
     } 

     private static SelectedConstructor FindNewConstructor(SelectedConstructor originalConstructor, Type interceptingType) 
     { 
      ParameterInfo[] parameters = originalConstructor.Constructor.GetParameters(); 
      SelectedConstructor selectedConstructor = new SelectedConstructor(interceptingType.GetConstructor(parameters.Select(pi => pi.ParameterType).ToArray())); 

      foreach (string newKey in originalConstructor.GetParameterKeys()) 
      { 
       selectedConstructor.AddParameterKey(newKey); 
      } 

      return selectedConstructor; 
     } 
    } 
} 

public class CustomInterception : Interception 
{ 
    protected override void Initialize() 
    { 
     this.Context.Strategies.AddNew<InstanceInterceptionStrategy>(UnityBuildStage.Setup); 
     this.Context.Strategies.AddNew<CustomTypeInterceptionStrategy>(UnityBuildStage.PreCreation); 
     this.Context.Container.RegisterInstance(typeof(AttributeDrivenPolicy).AssemblyQualifiedName, (InjectionPolicy)new AttributeDrivenPolicy()); 
    } 
}