假冒内存泄漏

时间:2011-02-09 14:37:00

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

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

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

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

1 个答案:

答案 0 :(得分:1)

很难说。至少,WindowsIdentity本身也是IDisposablenewId变量永远不会丢弃。另外,我会检查是否正确处理了Impersonator类的所有用途。