SqlCeConnection中的访问冲突异常处理

Ida*_*dan 6 .net c# dll access-violation sql-server-ce

申请/代码说明:

我的应用程序基于c#并使用SQL Server CE,并且在同一代码位置只有两次获得此异常.直到此版本才引入此例外的崩溃.此版本中唯一的变化是将.net框架更改为4.5.2.

我在处理a时遇到访问冲突异常SqlCeConnection,出现以下错误:

尝试读取或写入受保护的内存.这通常表明其他内存已损坏.

此异常不会被.net的try catch子句拦截 - 它会导致崩溃.

在我的代码中,我使用以下命令运行

try
{
    var connectionString = string.Format("{0}{1}{2}", "Data Source=", _localDB, ";File Mode=Read Write;Max Database Size=4000;Persist Security Info=False;");
    using (var sqlCeConnection = new SqlCeConnection(connectionString))
    {
        using (var sqlCeCommand = new SqlCeCommand())
        {
            sqlCeCommand.Connection = sqlCeConnection;
            sqlCeCommand.CommandText = "SELECT * FROM Application";
            sqlCeConnection.Open();
            var result = (string)sqlCeCommand.ExecuteScalar();
            isValid = !IsValid(result);
        }
    }
}
catch (Exception ex)
{
    _log.Error("exception", ex);
}
Run Code Online (Sandbox Code Playgroud)

第一次崩溃的调用堆栈:

ntdll!ZwWaitForMultipleObjects+a 
KERNELBASE!WaitForMultipleObjectsEx+e8 
kernel32!WaitForMultipleObjectsExImplementation+b3 
kernel32!WerpReportFaultInternal+215 
kernel32!WerpReportFault+77 
kernel32!BasepReportFault+1f 
kernel32!UnhandledExceptionFilter+1fc 
ntdll! ?? ::FNODOBFM::`string'+2365 
ntdll!_C_specific_handler+8c 
ntdll!RtlpExecuteHandlerForException+d 
ntdll!RtlDispatchException+45a 
ntdll!KiUserExceptionDispatcher+2e 
sqlcese35!__SafeRelease+c 
sqlcese35!Column::`vector deleting destructor'+5c 
sqlcese35!Object::DeleteObjects+39 
sqlcese35!Table::`vector deleting destructor'+45 
sqlcese35!Table::Release+27 
sqlcese35!HashTable::~HashTable+2a 
sqlcese35!Store::~Store+12b 
sqlcese35!Store::Release+2a 
sqlceme35!ME_SafeRelease+17 
DomainBoundILStubClass.IL_STUB_PInvoke(IntPtr ByRef)+78 
[[InlinedCallFrame] (System.Data.SqlServerCe.NativeMethods.SafeRelease)] System.Data.SqlServerCe.NativeMethods.SafeRelease(IntPtrByRef) 
System.Data.SqlServerCe.SqlCeConnection.ReleaseNativeInterfaces()+147 
System.Data.SqlServerCe.SqlCeConnection.Dispose(Boolean)+f1 
System_ni!System.ComponentModel.Component.Dispose()+18 
Run Code Online (Sandbox Code Playgroud)

第二次崩溃的调用堆栈:

ntdll!NtWaitForMultipleObjects+a 
KERNELBASE!WaitForMultipleObjectsEx+e8 
kernel32!WaitForMultipleObjectsExImplementation+b3 
kernel32!WerpReportFaultInternal+215 
kernel32!WerpReportFault+77 
kernel32!BasepReportFault+1f 
kernel32!UnhandledExceptionFilter+1fc 
ntdll! ?? ::FNODOBFM::`string'+2335 
ntdll!_C_specific_handler+8c 
ntdll!RtlpExecuteHandlerForException+d 
ntdll!RtlDispatchException+45a 
ntdll!KiUserExceptionDispatcher+2e 
<Unloaded_sqlcese35.dll>+7c88c 
<Unloaded_sqlceqp35.dll>+102790 
0x06ccc898 
0x06f9efc8 
0x1eca8018 
0x1f207400 
<Unloaded_sqlcese35.dll>+228dc 
0x00000004 
0x2edff008 
0x00000002 
0x00000003 
0x00000004 
<Unloaded_sqlcese35.dll>+3fbd9 
0x06ccc898 
DomainBoundILStubClass.IL_STUB_PInvoke(IntPtr ByRef)+78 
[[InlinedCallFrame] (System.Data.SqlServerCe.NativeMethods.SafeRelease)] System.Data.SqlServerCe.NativeMethods.SafeRelease(IntPtrByRef) 
System.Data.SqlServerCe.SqlCeConnection.ReleaseNativeInterfaces()+147 
System.Data.SqlServerCe.SqlCeConnection.Dispose(Boolean)+f1 
System_ni!System.ComponentModel.Component.Dispose()+1b 
Run Code Online (Sandbox Code Playgroud)

我在互联网上找到了一些建议,提出了一些解决方案:

  1. 可能的解决方案:检查同一连接上的多线程问题(尝试读取写保护的内存.这通常表明其他内存已损坏)

    拒绝:
    a.连接是在使用括号中创建的,不会被重用.
    湾 调用方法每5分钟调用一次,并通过转储文件验证它没有被同时调用.

  2. 可能的解决方案: sql ce版本不匹配(http://blogs.msdn.com/b/sqlservercompact/archive/2009/05/06/troubleshooting-access-violation-exception-while-using-sql-server-compact-database- with-ado-net-provider.aspx)

    可能的拒绝:我在安装的版本中看到的是3.5 SP2(3.5.8080.0)并且从转储中的模块我可以看到 sqlceme35.dll,System.Data.SqlServerCe.dllDLL的版本是3.05.8080.0

  3. 可能的解决方案有以下几点:https: //stackoverflow.com/a/20492181/1447518

    可能的拒绝:从统计角度来看听起来不对 - 代码在同一个地方崩溃了两次,尽管在应用程序代码中有另一个地方写入和读取到不同的数据库并且应用程序没有在那里崩溃.

  4. 我想到的最后一件事,可能会建议DLL的卸载问题(看看第二个调用堆栈).我的猜测是dll是从应用程序中卸载的,而应用程序需要它们才能进行处理,但它接缝有点模糊和"长镜头"

我的问题是:什么可能导致问题,什么是可能的解决方案?

Ida*_*dan 2

虽然这个方案还没有得到验证,但是解决方案如下:

从第二个调用堆栈中我可以看到本地 DLL 已卸载,我的猜测是 SQL 连接的处置方法正在使用它当前处置的方法之一。我彻底验证了进程转储,所有 SqlCeConnection 类型都在处理过程中。

看到 ErikEj 评论让我意识到,如果我看看 SQL-CE 3.5 到 4.0 (System.Data.SqlServerCe.dll) 之间的代码差异会更好。

查看代码后,我可以看到释放的方法被移动到了 dispose 方法中较靠后的位置。

此外,我可以看到,在调用 SafeRelease 之前,还有另一个检查,检查安全释放所需的本机 DLL 是否已被释放,并引发异常。

底线是,SQL-CE 4.0 对于同一问题有 2 个解决方案。

我的猜测是这个问题是因此引起的。

目前的解决方案是在整个应用程序生命周期中保持连接(没有连接字符串),这会导致指针池在整个应用程序生命周期中将本机 Dll 保留在内存中。

更好的解决方案是迁移到 SQL-CE 4.0 。