0

因此,我们遇到了一个问题,即容器在应用程序期间持有 DerivedTypeConstructorSelectorPolicy 的实例。如果不是因为 TypeInterceptionStrategy 中的以下两行代码将旧策略包装到一个新策略中,那么这不会那么糟糕,然后它现在保存两个实例(或更多,每次调用 Resolve 以获取拦截的类会使问题复杂化)。您可以在运行 .NET Memory Profiler 时看到这一点。

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);

当你有很多类被拦截时,这会导致 Gen 2 集合崩溃,然后你会在内存中出现 GC 无法回收的漏洞,尤其是在复制策略以确保线程安全时。一旦您在策略列表中有足够数量的项目,它将被移至 LOH,这使得颠簸更加严重。

我应该警告这一点,因为我们的应用程序在 IIS Classic 中运行,而不是在集成管道和 32 位模式下运行,我知道这是双重打击。在 64 位模式下有更多的可寻址空间,这不会那么糟糕。但是,我们仍然被 IIS 提供给我们的虚拟内存卡住了,这很快就发生了,因为 GC 无法在 VM 映射中找到足够的空间来分配额外的内存并且请求开始死亡。

该文件只有 3 个修订版,原始修订版看起来没有这个问题。有没有其他人遇到过这个问题,或者我错过了一些可能解释这种行为的东西?

pastebin 上发布了一个非常简单的程序的链接来说明这一点:http: //pastebin.com/DYG3GXNm

使用 .NET 内存探查器(或您选择的探查器)并观察 DerivedTypeConstructorSelectorPolicy,您可以观察它在每次迭代中的增长,并且随着它的增长,您可以检查并看到 originalConstructorSelectorPolicy 一直引用长链中的旧实例。

作为我们拦截多少类的一个例子,它大约有 1300 个左右的注册。

4

1 回答 1

1

在此期间,我找到了解决方案。这是一个简单的修复,但它要求您覆盖 Interception 和 TypeInterceptionStrategy。修复是一个单行程序,仅涉及检查策略列表中出现的类型。

这是来自 TypeInterceptionStrategy 的代码:

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

当然,为了改变它,你必须复制 TypeInterceptionStrategy 并做与修复相同的事情,它不能简单地通过覆盖 PreBuildUp 方法来修复。

我将整个修复粘贴在这里,以防其他人遇到问题。

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());
    }
}
于 2012-12-05T20:16:55.603 回答