在与自定义声明提供商合作时,我发现了有趣的事情 SPActiveDirectoryClaimProvider. 。如果您使用任何 .net 程序集浏览器\反编译器(.NET Reflector 或 ILSpy)调查代码,您会发现内存泄漏 SPWeb 方法中的对象 FillResolve. 。仔细看看代码:

// Microsoft.SharePoint.Administration.Claims.SPActiveDirectoryClaimProvider
private void FillResolve(Uri context, string[] entityTypes, bool inputIsEmailOnly, string resolveInput, List<PickerEntity> resolved)
{
    SPWeb sPWeb = null;
    SPSite sPSite = null;
    if (!SPThreadContext.Items.Contains("SPActiveDirectoryClaimProviderIgnoreContext"))
    {
        bool catchAccessDeniedException = SPSecurity.CatchAccessDeniedException;
        try
        {
            SPSecurity.CatchAccessDeniedException = false;
            sPSite = new SPSite(context.AbsoluteUri);
            if (sPSite != null)
            {
                sPWeb = sPSite.OpenWeb();
            }
            if (!sPWeb.Exists)
            {
                sPWeb = null;
            }
        }
        catch
        {
            if (sPSite != null)
            {
                sPSite.Dispose();
                sPWeb = null;
            }
        }
        finally
        {
            SPSecurity.CatchAccessDeniedException = catchAccessDeniedException;
        }
    }
    try
    {
        SPWebApplication webApp = SPWebApplication.Lookup(context);
        SPPrincipalType scopes = SPActiveDirectoryClaimProvider.ConvertEntityTypeToPrincipalTypes(entityTypes);
        SPPrincipalInfo sPPrincipalInfo = SPUtility.ResolveWindowsPrincipal(sPWeb, webApp, resolveInput, scopes, inputIsEmailOnly);
        if (sPPrincipalInfo != null)
        {
            if (inputIsEmailOnly && MatchType.EmailAddress == sPPrincipalInfo.MatchType && SPActiveDirectoryClaimProvider.DisableEmailResolve())
            {
                ULS.SendTraceTag(2466693u, ULSCat.msoulscat_WSS_ClaimsAuthentication, ULSTraceLevel.VerboseEx, "Dicarding match '{0}' for input '{1}' because it is email match and feature is disabled.", new object[]
                {
                    sPPrincipalInfo.LoginName,
                    resolveInput
                });
            }
            else
            {
                PickerEntity pickerEntity = this.CreatePickerEntity(sPPrincipalInfo);
                if (pickerEntity != null)
                {
                    resolved.Add(pickerEntity);
                    ULS.SendTraceTag(1634481712u, ULSCat.msoulscat_WSS_ClaimsAuthentication, ULSTraceLevel.VerboseEx, string.Format(CultureInfo.InvariantCulture, "Returning AD resolve match '{0}' for input '{1}'.", new object[]
                    {
                        pickerEntity.Key,
                        resolveInput
                    }));
                }
            }
        }
        else
        {
            if (!inputIsEmailOnly)
            {
                int maxCount = 10;
                bool flag = false;
                IList<SPPrincipalInfo> list;
                if (sPWeb != null)
                {
                    list = SPUtility.SearchPrincipals(sPWeb, resolveInput, scopes, SPPrincipalSource.Windows, null, maxCount, out flag);
                }
                else
                {
                    list = SPUtility.SearchWindowsPrincipals(webApp, resolveInput, scopes, maxCount, out flag);
                }
                List<PickerEntity> list2 = new List<PickerEntity>();
                foreach (SPPrincipalInfo current in list)
                {
                    if (inputIsEmailOnly && MatchType.EmailAddress == current.MatchType && SPActiveDirectoryClaimProvider.DisableEmailResolve())
                    {
                        ULS.SendTraceTag(2466694u, ULSCat.msoulscat_WSS_ClaimsAuthentication, ULSTraceLevel.VerboseEx, "Dicarding match '{0}' for input '{1}' because it is email match and feature is disabled.", new object[]
                        {
                            current.LoginName,
                            resolveInput
                        });
                    }
                    else
                    {
                        PickerEntity pickerEntity2 = this.CreatePickerEntity(current);
                        if (pickerEntity2 != null)
                        {
                            list2.Add(pickerEntity2);
                            ULS.SendTraceTag(1634481713u, ULSCat.msoulscat_WSS_ClaimsAuthentication, ULSTraceLevel.VerboseEx, string.Format(CultureInfo.InvariantCulture, "Returning AD resolve search match '{0}' for input '{1}'.", new object[]
                            {
                                pickerEntity2.Key,
                                resolveInput
                            }));
                        }
                    }
                }
                if (list2.Count == 1 && list2[0].Claim != null && SPClaim.EqualClaimValues(list2[0].Claim.Value, resolveInput))
                {
                    resolved.Add(list2[0]);
                }
                else
                {
                    if (list2.Count > 0)
                    {
                        PickerEntity pickerEntity = base.CreatePickerEntity();
                        pickerEntity.IsResolved = false;
                        pickerEntity.DisplayText = resolveInput;
                        pickerEntity.MultipleMatches.AddRange(list2);
                        resolved.Add(pickerEntity);
                    }
                }
            }
        }
    }
    catch
    {
        throw;
    }
    finally
    {
        if (sPSite != null)
        {
            sPSite.Dispose();
        }
    }
} 

根据最佳实践(http://msdn.microsoft.com/en-us/library/office/ee557362%28v=office.14%29.aspx)我们应该处置 SPWeb 使用创建的对象 OpenWeb 方法。但 sPWeb 对象未在该方法的任何部分中释放。这意味着,每次我们在人员选择器中执行搜索和解析时,都会有一个 SPWeb 对象将会被泄露。我没有 msdn 订阅,无法联系 Microsoft 解决此问题。对于 SharePoint 2010 (SP2) 和 SharePoint 2013 (SP1) 来说,存在此问题。

我相信社区可以确认内存泄漏并联系微软来解决这个问题。

有帮助吗?

解决方案

在使用 OpenWeb 方法的 SPSite 上调用 Dispose() 将自动释放它打开的 SPWeb。只要 SPSite 被处置,您就不会遇到问题,除非您打开大量 SPWeb 并且没有明确处置它们。

查看该代码,它似乎正在处理 SPSite,因此应该没问题。

编辑

作为参考,以下是 .Dispose() 方法调用的 SPSite 类中的 .Close() 方法。正如您所看到的,它在处置自身之前处置了它打开的所有 SPWeb:

public void Close()
{
    SPEventManager.WaitForPostEvents();
    if (this.m_openedWebs != null)
    {
        SPWeakObjectHandleList<SPWeb> list = new SPWeakObjectHandleList<SPWeb>(this.m_openedWebs);
        foreach (SPWeb web in list)
        {
            web.Close();
        }
        list.Dispose();
        this.m_openedWebs.Dispose();
    }
    this.m_rootWebCreated = false;
    SPRequestContext.UnregisterSite(this);
    this.InvalidateSite();
}
许可以下: CC-BY-SA归因
scroll top