【问题标题】:What is the cause of this OutOfMemoryException on Mutex constructor?Mutex 构造函数上的这个 OutOfMemoryException 的原因是什么?
【发布时间】:2016-12-14 10:35:34
【问题描述】:

我在这行代码中得到了System.OutOfMemoryException

mutex2 = new Mutex(true, "Name2");

这是堆栈跟踪:

{"Exception of type 'System.OutOfMemoryException' was thrown."}
   at Microsoft.Win32.Win32Native.CreateMutex(SECURITY_ATTRIBUTES lpSecurityAttributes, Boolean initialOwner, String name)
   at System.Threading.Mutex.CreateMutexHandle(Boolean initiallyOwned, String name, SECURITY_ATTRIBUTES securityAttribute, SafeWaitHandle& mutexHandle)
   at System.Threading.Mutex.MutexTryCodeHelper.MutexTryCode(Object userData)
   at System.Runtime.CompilerServices.RuntimeHelpers.ExecuteCodeWithGuaranteedCleanup(TryCode code, CleanupCode backoutCode, Object userData)
   at System.Threading.Mutex.CreateMutexWithGuaranteedCleanup(Boolean initiallyOwned, String name, Boolean& createdNew, SECURITY_ATTRIBUTES secAttrs)
   at System.Threading.Mutex..ctor(Boolean initiallyOwned, String name, Boolean& createdNew, MutexSecurity mutexSecurity)
   at System.Threading.Mutex..ctor(Boolean initiallyOwned, String name)
   at Foo.FooDefinitions.FooManager.FooForm.FooForm_Load(Object sender, EventArgs e) in c:\tfs\DWS\TRUNK\DEV\FooDefinitions\FooManager\FooForm.cs:line 92

只有在我使用模拟时才会发生。如果没有模拟(在我的普通 Windows 帐户上运行),它将运行良好。模仿是这样的:

    if (!NativeMethods.LogonUser(userName, domainName, password, 2, 0, ref this._tokenHandle)) // [DllImport("advapi32.dll", SetLastError = true, CharSet = CharSet.Auto)]
    {
        throw new Win32Exception(Marshal.GetLastWin32Error());
    }
    this._impersonatedUser = new WindowsIdentity(this._tokenHandle).Impersonate();

编辑:为了详细说明,我正在对遗留代码创建自动化测试。如果可以的话,我会删除互斥锁的使用。我目前正在调查 Mutex 构造函数上的SecurityCriticalAttribute

EDIT2:这是完整的代码示例:

using Microsoft.VisualStudio.TestTools.UnitTesting;
using System;
using System.ComponentModel;
using System.Net;
using System.Runtime.InteropServices;
using System.Security.Principal;
using System.Threading;

namespace ReinierDG.MutexTesting
{
    [TestClass]
    public class MutexTest
    {
        [TestMethod]
        public void CreateMutexUnderImpersonation()
        {
            var credentials = new NetworkCredential("testagent", "secretpassword");
            var tokenHandle = new IntPtr();
            if (!NativeMethods.LogonUser(credentials.UserName, credentials.Domain, credentials.Password, 2, 0, ref tokenHandle))
            {
                throw new Win32Exception(Marshal.GetLastWin32Error());
            }
            var impersonatedUser = new WindowsIdentity(tokenHandle).Impersonate();
            // this will run indefinately or untill memory is full with 1 cpu core at 100%
            var mutex = new Mutex(true, "test");
        }

        internal static class NativeMethods
        {
            [DllImport("advapi32.dll", SetLastError = true, CharSet = CharSet.Auto)]
            internal static extern bool LogonUser([MarshalAs(UnmanagedType.LPWStr)]string lpszUsername, [MarshalAs(UnmanagedType.LPWStr)]string lpszDomain, [MarshalAs(UnmanagedType.LPWStr)]string lpszPassword, int dwLogonType, int dwLogonProvider, ref IntPtr phToken);
        }
    }
}

【问题讨论】:

  • Here 是来源。它在while(true) 内显示CreateMutex;也许你发现了一个无限循环错误?
  • FooForm.FooForm_Load 方法的代码
  • 但首先:您确定需要互斥体吗?在表单加载事件中???
  • 你能在问题中发布完整的代码(不仅仅是链接到它)吗?
  • 您应该避免使用Mutex(bool, string) 创建命名互斥锁。另请参阅 here - 请改用 Mutex(bool, string, out bool)。你确定你需要一个名为Mutex吗?

标签: c# .net out-of-memory mutex impersonation


【解决方案1】:
    // this will run indefinately or untill memory is full

嗯,这是一种解释。我们必须假设注释与代码不匹配。这里最明显的问题是您没有发布与错误足够相关的堆栈跟踪,并且不会帮助您诊断潜在问题。我只能发布提示让您进入下一阶段。

很容易假设是 CreateMutex() 失败了。然而事实并非如此,winapi 函数失败的报告方式不同,您会在堆栈跟踪中看到__Error.WinIOError()。并且错误代码会有所不同,您会收到错误 1450,ERROR_NO_SYSTEM_RESOURCES,“系统资源不足,无法完成请求的服务”。

实际上是 CLR 引发了异常。或者换句话说,失败的是 pinvoke marshaller。这使诊断变得相当复杂,在非常大量的代码中有非常多的地方可以引发 OOM。它通常需要分配非托管内存来完成 pinvoke 工作,如果失败,那么你会得到 OOM-kaboom。可能发生的方式很多,内部非托管堆损坏当然就足够了。您的 LogonUser() pinvoke 声明在技术上是错误的 (CharSet.Auto != UnmanagedType.LPWStr),但还不足以解释这个问题。

您需要更接近异常的根源,这需要启用非托管调试器。对于 VS2015,使用项目 > 属性 > 调试选项卡 > 勾选“启用本机代码调试”复选框。您需要调试 CLR 的符号才能理解堆栈跟踪。使用工具 > 选项 > 调试 > 符号 > 勾选“Microsoft 符号服务器”。您需要让调试器在第一次出现异常时停止,使用 Debug > Windows > Exception Settings > 勾选“Win32 Exceptions”。

您现在会知道更多,您可以在问题中发布更好的堆栈跟踪。尽管如此,这将为 SO 用户或您提供清晰的诊断以显示如何通过冒充来解释此事故的可能性很小。寻求 Microsoft 支持的帮助是明智的,但是他们需要更多地了解该“testagent”帐户的确切配置方式。请记住,此类帐户通常会被故意禁用,以确保单元测试不会占用太多系统资源。

【讨论】:

    【解决方案2】:

    您可以使用 LOGON32_LOGON_NEW_CREDENTIALS(9) 作为 LogonType 和 LOGON32_PROVIDER_WINNT50(3) 作为 LogonProvider,它会成功。我认为是关于authority

    当您在代码中调试它时,您可以在无限 loop 中找到它,mutexHandle = Win32Native.CreateMutex(securityAttribute, initiallyOwned, name);ERROR_ACCESS_DENIED 失败。它将运行 Win32Native.OpenMutex(Win32Native.MUTEX_MODIFY_STATE | Win32Native.SYNCHRONIZE, false, name);,但它也因 ERROR_FILE_NOT_FOUND

    而失败

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2017-06-22
      • 1970-01-01
      • 2016-01-27
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-08-11
      • 1970-01-01
      相关资源
      最近更新 更多