【发布时间】:2016-09-07 20:55:10
【问题描述】:
我有一个编写为 Windows 服务的 .NET 4 应用程序,其中包括非托管组件,并且正在向我的 log4net 日志打印 AccessViolationException,但没有使应用程序崩溃。关于这个问题的一切听起来都是不可能的。以下是我认为正在发生的事情,我想知道作为开发人员的下一步应该是什么?此问题不会发生在与生产具有相同数据馈送的并行重放环境中。
- 内存损坏问题表现为 AccessViolationException,堆栈跟踪归咎于 SSIS 运行时“DTS”。
- DataLoaderWinSvc.exe 是一个 .NET 4 应用程序,注册/运行为 Windows 本地服务。
- Microsoft 更改了 .NET 4 中的 CLR,以便 AccessViolationException 在默认情况下导致应用程序崩溃。
- 但是,DataLoaderWinSvc.exe 不会崩溃。这让我开始调查这怎么可能?
- 有一种方法可以让开发人员在 .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属性 抛出异常的方法。
- 根据 DataLoaderWinSvc.txt log4net 日志,很明显,尽管 DataLoaderWinSvc.exe 作为 .NET Framework 4 应用程序运行,但仍能够处理此异常,否则我们将没有任何日志记录语句并且只会崩溃。但是,根本没有崩溃。
- 通过使用 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 程序集。
- 看起来,基于 Process Explorer.exe,虽然我调用的 Microsoft.SQLServer.ManagedDTS.dll 是一个 .NET 4 程序集,但它实际上将工作委托给了一个带有本机的 CLR v2.0.50727 程序集图像(ngen 的程序集)。
- 如果 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