【问题标题】:What to do when AccessViolationException in .NET 4 app defies MSDN documented behavior?当 .NET 4 应用程序中的 AccessViolationException 违反 MSDN 记录的行为时该怎么办?
【发布时间】:2016-09-07 20:55:10
【问题描述】:

我有一个编写为 Windows 服务的 .NET 4 应用程序,其中包括非托管组件,并且正在向我的 log4net 日志打印 AccessViolationException,但没有使应用程序崩溃。关于这个问题的一切听起来都是不可能的。以下是我认为正在发生的事情,我想知道作为开发人员的下一步应该是什么?此问题不会发生在与生产具有相同数据馈送的并行重放环境中。

  1. 内存损坏问题表现为 AccessViolationException,堆栈跟踪归咎于 SSIS 运行时“DTS”。
  2. DataLoaderWinSvc.exe 是一个 .NET 4 应用程序,注册/运行为 Windows 本地服务。
  3. Microsoft 更改了 .NET 4 中的 CLR,以便 AccessViolationException 在默认情况下导致应用程序崩溃。
  4. 但是,DataLoaderWinSvc.exe 不会崩溃。这让我开始调查这怎么可能?
  5. 有一种方法可以让开发人员在 .NET 4 中处理异常,但 DataLoaderWinSvc.exe 代码没有使用 [HandleProcessCorruptedStateExceptions] 技术。 https://msdn.microsoft.com/en-us/library/system.accessviolationexception(v=vs.110).aspx#Anchor_6:

从 .NET Framework 4 开始,AccessViolationException 公共语言运行时抛出的异常不被处理 如果异常,结构化异常处理程序中的 catch 语句 发生在公共语言运行库保留的内存之外。 要处理这样的AccessViolationException 异常,您应该申请 HandleProcessCorruptedStateExceptionsAttribute 属性 抛出异常的方法。

  1. 根据 DataLoaderWinSvc.txt log4net 日志,很明显,尽管 DataLoaderWinSvc.exe 作为 .NET Framework 4 应用程序运行,但仍能够处理此异常,否则我们将没有任何日志记录语句并且只会崩溃。但是,根本没有崩溃。
  2. 通过使用 Process Explorer.exe,我检查了部署的代码版本是否不使用 .NET 4 Framework。 - 这就是我开始看到可疑的地方!事实证明,SSIS 运行时 DLL d:\Program Files (x86)\Microsoft SQL Server\120\SDK\Assemblies\Microsoft.SQLServer.ManagedDTS.dll 是一个 .NET 2.0 程序集。
  3. 看起来,基于 Process Explorer.exe,虽然我调用的 Microsoft.SQLServer.ManagedDTS.dll 是一个 .NET 4 程序集,但它实际上将工作委托给了一个带有本机的 CLR v2.0.50727 程序集图像(ngen 的程序集)。
  4. 如果 AccessViolationException 发生在 CLR v2.0.50727 程序集中,那么这可能就是我们能够捕获这个所谓的无法捕获的异常的方式。

这是匿名的堆栈跟踪:

2016-08-16 20:58:38,207 错误:编排:初始化 System.AccessViolationException:试图读或写保护 记忆。这通常表明其他内存已损坏。
在 Microsoft.SqlServer.Dts.Runtime.Package.Execute() 在 DataLoader.Orchestration.DoWork() 在 D:\SourceCode\DataLoader\Mainline\Core\Orchestration.cs:第 198 行 System.AccessViolationException:试图读或写保护 记忆。这通常表明其他内存已损坏。
在 Microsoft.SqlServer.Dts.Runtime.Package.Execute() 在 DataLoader.Orchestration.DoWork() 在 D:\SourceCode\DataLoader\Mainline\Core\Orchestration.cs:198行

这里大致是一个近似于代码在做什么的 sn-p:

public class Orchestration
{
  private Application m_DTSApplication;
  private Package m_DTSPackage;

  public IntradayOrchestration()
  {
    InitializeDTSPackage();
  }

  private void InitiatlizeDTSPackage()
  {
    m_DTSPackageLocation = ConfigurationManager.AppSettings["DTSPackageLocation"].ToString();
    m_DTSPackageConfigLocation = ConfigurationManager.AppSettings["DTSPackageConfigLocation"].ToString();

    m_DTSApplication = new Application();
    m_DTSApplication.PackagePassword = ConfigurationManager.AppSettings["DTSPackagePassword"];

    m_DTSPackage = m_DTSApplication.LoadPackage(m_DTSPackageLocation, null);
    m_DTSPackage.ImportConfigurationFile(m_DTSPackageConfigLocation);       
  }

  private void DoWork()
  {
    try
    {
      Stopwatch sw = Stopwatch.StartNew();
      while (true)
      {
        sw.Start();
        DTSExecResult result = m_DTSPackage.Execute();                                           
        sw.Stop();
        Logger.ReportInfo(DateTime.Now.ToString() + "Time taken by dts package= " + sw.ElapsedMilliseconds.ToString());

        // Check retuns status and check for errors on Job execution
        if (result != DTSExecResult.Success || m_DTSPackage.Errors != null)
        {
          if (m_DTSPackage.Errors != null)
          {
            foreach (DtsError error in m_DTSPackage.Errors)
            {
              string errorMesg = string.Format("Orchestration: SSIS Package [{0}] Error: Code[{1}] Source[{2}] Component[{3}] Description[{4}]", m_DTSPackage.Name, error.ErrorCode, error.Source, error.SubComponent, error.Description);
              Logger.ReportError(errorMesg, new ApplicationException(errorMesg));
            }
          }
          else
          {
            string errorMesg = string.Format("Orchestration: SSIS Package [{0}] did not complete successfully. Return status [{1}]", m_DTSPackage.Name, result.ToString());
            Logger.ReportError(errorMesg, new ApplicationException(errorMesg));
          }
        }
        else
        {
          Logger.ReportInfo(
            string.Format("Orchestration: SSIS Package [{0}] completed successfully", m_DTSPackage.Name));
        }
     }
     catch (Exception ex)
     {
        Logger.ReportError(
            string.Format("Orchestration: SSIS Package [{0}] completed successfully", m_DTSPackage.Name));
     }
  }
}

【问题讨论】:

    标签: c# ssis access-violation


    【解决方案1】:

    根本原因实际上是由于跨运行时环境从 .NET 4 到 .NET 2 造成的“空域”。

    此外,事实证明 SQL Server 2008 R2 SSIS 运行时可能在 SQL 日志记录子组件中存在双重可用内存错误。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2012-06-23
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-03-29
      • 2014-07-11
      • 1970-01-01
      相关资源
      最近更新 更多