【问题标题】:Impersonation memory leak模拟内存泄漏
【发布时间】:2011-02-09 14:37:00
【问题描述】:

http://msdn.microsoft.com/en-us/library/w070t6ka(v=VS.100).aspx 上有一个关于如何使用 .net 4.0 进行模拟的示例。为了便于使用,我们在继承 IDisposable 的类中使用了这个示例。但是,当我们在 asp.net Web 应用程序中使用此类时,我们注意到性能监视器中的 Pool Paged Bytes 略有但稳定增加。一周后,应用程序崩溃。

我尝试了模拟类的不同实现,使用 http://msdn.microsoft.com/en-us/library/w070t6ka(v=VS.90).aspxhttp://support.microsoft.com/kb/306158 作为参考,但它们都显示相同的泄漏。

这种泄漏是从哪里来的? windows api有问题吗?我们正在运行 Windows 2008 R2。

这是我们当前版本的模拟类:

public class Impersonator : IDisposable
{
    public Impersonator(string username, string domain, string password)
    {
        if (!ImpersonateValidUser(username, domain, password))
        {
            throw new SecurityException("Could not impersonate. Wrong username / password");
        }
    }

    public void Dispose()
    {
        UndoImpersonation();
    }

    [DllImport("advapi32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
    private static extern bool LogonUser(String lpszUsername, String lpszDomain, String lpszPassword, int dwLogonType, int dwLogonProvider, out SafeTokenHandle phToken);

    private const int LOGON32_PROVIDER_DEFAULT = 0;
    private const int LOGON32_LOGON_INTERACTIVE = 2; //This parameter causes LogonUser to create a primary token.

    private WindowsImpersonationContext impersonatedUser;

    private bool ImpersonateValidUser(string username, string domain, string password)
    {
        SafeTokenHandle safeTokenHandle;

        // Call LogonUser to obtain a handle to an access token.
        bool success = LogonUser(username, domain, password, LOGON32_LOGON_INTERACTIVE, LOGON32_PROVIDER_DEFAULT, out safeTokenHandle);

        if (success)
        {
            using (safeTokenHandle)
            {
                // Use the token handle returned by LogonUser.
                WindowsIdentity newId = new WindowsIdentity(safeTokenHandle.DangerousGetHandle());
                impersonatedUser = newId.Impersonate();
            }
        }

        return success;
    }

    private void UndoImpersonation()
    {
        // Releasing the context object stops the impersonation
        if (impersonatedUser != null)
        {
            impersonatedUser.Undo();
            impersonatedUser.Dispose();
        }
    }
}

public sealed class SafeTokenHandle : SafeHandleZeroOrMinusOneIsInvalid
{
    private SafeTokenHandle() : base(true)
    {
    }

    [DllImport("kernel32.dll")]
    [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)]
    [SuppressUnmanagedCodeSecurity]
    [return: MarshalAs(UnmanagedType.Bool)]
    private static extern bool CloseHandle(IntPtr handle);

    protected override bool ReleaseHandle()
    {
        return CloseHandle(handle);
    }
}

这是使用不同版本的类的两个网络服务器的性能监控图:

perfmon http://img222.imageshack.us/img222/5388/captureyog.png

当我们禁用该类并通过 web.config 使用全局模拟时,这些行是完全平坦的。


更新

我已经制作了一个成功重现问题的测试应用程序。可以在这里下载:

http://rapidshare.com/files/447325211/ImpersonationTest.zip

18 小时后的结果如下所示:

testapp http://img689.imageshack.us/img689/2055/impersonationtest.png

【问题讨论】:

  • 我查看了您的代码和 SafeHandleZeroOrMinusOneIsInvalid 的实现(通过 Reflector)。我确定我可能错过了一些东西,但我不清楚从哪里调用 CloseHandle 或 ReleaseHandle。 Are you expecting this to be called by the inherited Dispose method on SafeTokenHandle?
  • 我不知道它是如何工作的,我只是假设它确实如此,因为它是从上面链接中的微软网站复制而来的。我添加了几行调试,在模拟完成后它确实会被调用,但这就是我所知道的。
  • 鉴于您所说的以及其他样本明确关闭句柄,那么它似乎不是问题。你有 MSDN 订阅吗?如果是这样,您可以使用 Microsoft 支持事件来获得更多帮助。
  • 是的,我们订阅了 MSDN,但由于我似乎无法在本地重现该问题,我认为这不会有帮助。
  • 没关系,我用有关如何重现泄漏的信息更新了我的问题。

标签: c# asp.net winapi memory-leaks


【解决方案1】:

很难说。至少,WindowsIdentity 本身也是一个IDisposable,而newId 变量永远不会被丢弃。另外,我会检查 Impersonator 类的所有使用是否都被正确处理。

【讨论】:

  • 类的所有使用都在 using 语句中进行,因此应该是安全的。不过,使用 newId 变量很好,我会解决这个问题并明天将其发送测试。
  • 与该更新相同的结果。我还在我们的开发环境中制作了一个测试应用程序,但我似乎无法复制那里的泄漏。在 100 万次模拟之后,池分页字节保持不变,所以我真的不知道从哪里开始。
  • 我也很茫然。如果没有额外的信息(并且给定场景,很可能是:没有完整的应用程序),就无法判断。我不希望处置 WindowsIdentity 可以解决问题,但是唉。
  • 我现在已经设法重现泄漏,现在在我的问题中找到了完整的应用程序。
  • 在我更改了我的测试应用程序以更好地复制生产环境的行为(在模拟期间创建和删除网络共享上的文件)之后,
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2013-12-27
  • 2011-09-03
  • 1970-01-01
  • 2011-09-26
  • 2014-01-22
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多