模拟内存泄漏

7
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


我已经查看了您的代码以及通过Reflector实现SafeHandleZeroOrMinusOneIsInvalid。我确定我可能错过了一些东西,但我不清楚CloseHandle或ReleaseHandle从哪里调用。您是否希望这是由继承的SafeTokenHandle上的Dispose方法调用的? - MikeD
我不知道它是如何工作的,我只是假设它能够工作,因为它是从上面链接中微软的网站复制过来的。我添加了几行调试代码,它确实在模拟完成后被调用,但这就是我所知道的全部。 - TheQ
根据您的说法以及其他示例明确关闭句柄,那么这似乎不是问题所在。您是否拥有MSDN订阅?如果是,您可以使用Microsoft支持事件来获得一些额外的帮助。 - MikeD
是的,我们有MSDN订阅,但由于我似乎无法在本地重现这个问题,所以我不认为那会有帮助。 - TheQ
没关系,我更新了我的问题,并提供了如何复制泄漏的信息。 - TheQ
我在一个Web服务中遇到了同样的问题。你是如何解决这个问题的? - Meryovi
1个回答

1
很难说。至少,WindowsIdentity 本身也是一个 IDisposable,而 newId 变量从未被处理。此外,我会检查所有使用 Impersonator 类的地方是否都被正确处理。

所有对该类的使用都在using语句中完成,因此应该是安全的。关于newId变量的好考虑,我会修复它并明天发送给测试。 - TheQ
同样的结果与那次更新没有变化。我在我们的开发环境中也制作了一个测试应用程序,但是似乎无法在那里复制泄漏。经过100万次模拟,池页面字节数保持不变,所以我真的不知道该从哪里开始。 - TheQ
我也感到困惑。没有额外的信息(考虑到情况,很可能是:没有完整的应用程序),无法确定原因。我并不抱有太大希望,认为处理WindowsIdentity可能会奏效,但遗憾的是并没有。 - Willem van Rumpt
我现在成功地复现了泄漏问题,并且完整的应用程序已经包含在我的问题描述中。 - TheQ
在我将测试应用程序修改为更好地复制生产环境的行为(在模拟登录期间创建和删除网络共享中的文件)之后, - TheQ
应用程序是否模仿了asp.net应用程序的实际行为(例如:数百万次模拟和文件写入)?当我运行应用程序时,无论是否使用模拟,池分页字节数都会增加。如果这接近真实情况,可能只是运行时没有足够的时间释放资源,压力不断增加。通过在线程过程中简单地添加Thread.Sleep(50),PPB增量保持在零左右,甚至变为负值。 - Willem van Rumpt

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接