Mono + Linux + SQlite->不好的做法 - >结果无法打开数据库文件

时间:2013-06-10 08:21:39

标签: linux windows sqlite mono

找到了有趣的问题:D

许多人在Mono + Linux中询问为什么在打开SQLite数据库时有时会发生“无法打开数据库文件”。

几天后,我们发现一个隐藏的问题让我疯了。

考虑以下代码(请不要评论风格,因为这不是重点!

System.Data.SQLite.SQLiteConnectionStringBuilder sqcsb;
sqcsb = new System.Data.SQLite.SQLiteConnectionStringBuilder();
sqcsb.DataSource = "file.db";
sqcsb.SyncMode = System.Data.SQLite.SynchronizationModes.Full;
sqcsb.PageSize = 4096;

System.Data.SQLite.SQLiteConnection conn;
System.Data.SQLite.SQLiteCommand cmd;
System.Data.SQLite.SQLiteParameter param;
string sql = "update Smth set tt = @TT";
int i = 0;
while (true)
{
    GC.Collect();
    System.Diagnostics.Process proc = System.Diagnostics.Process.GetCurrentProcess();
    Console.WriteLine("Memory:{0:0,0},Private: {1:0,0},Virtual: {2:0,0} Working: {3:0,0}, Paged: {4:0,0}",
    GC.GetTotalMemory(true),
    proc.PrivateMemorySize64,
    proc.VirtualMemorySize64,
    proc.WorkingSet64,
    proc.PagedMemorySize64);    

    Console.WriteLine( "Testing DB..." + i++);
    conn = new System.Data.SQLite.SQLiteConnection(sqcsb.ConnectionString);
    conn.Open();
    cmd = new System.Data.SQLite.SQLiteCommand(conn);
    cmd.CommandText = sql;

    param = new System.Data.SQLite.SQLiteParameter("@TT", DbType.String);
    param.Value = "0";
    cmd.Parameters.Add(param);


    conn.Close();
    conn.Dispose();
    cmd.Dispose();
}

那么上面的代码有什么问题?

答案是我们在cmd.Dispose()之前调用conn.Dispose(),它在WINDOWS上运行没有任何问题,而在Mono和Linux上,它在上述代码的大约1000个循环中失败,带有Sqlite异常无法打开数据库文件

在此处开始处理输出:

Memory:671,744,Private: 5,091,328,Virtual: 19,202,048 Working: 9,617,408, Paged: 00
Testing DB...0
Memory:770,048,Private: 5,763,072,Virtual: 23,617,536 Working: 11,341,824, Paged: 00
Testing DB...1
Memory:770,048,Private: 5,763,072,Virtual: 23,617,536 Working: 11,341,824, Paged: 00
Testing DB...2

这是最后一个WriteLine输出:

Memory:778,240,Private: 125,104,128,Virtual: 142,958,592 Working: 130,654,208, Paged: 00
Testing DB...1019

Unhandled Exception: System.Data.SQLite.SQLiteException: unable to open database file
  at System.Data.SQLite.SQLite3.Open (System.String strFilename, SQLiteConnectionFlags     connectionFlags, SQLiteOpenFlagsEnum openFlags, Int32 maxPoolSize, Boolean usePool)     [0x00000] in <filename unknown>:0 
  at System.Data.SQLite.SQLiteConnection.Open () [0x00000] in <filename unknown>:0 

在崩溃的最后,你可以看到进程的PrivateMemory和VirtualMemory非常高。

它们在每次打开到db的连接时都会增加,这意味着它可能不会从内存中释放出来!

所以找到困难的方法..解决问题的方法是......改变这一点:

    conn.Dispose();
    cmd.Dispose();

为:

    cmd.Dispose();
    conn.Dispose();

我知道上面的代码不是本书的最佳实践,但仍然有很多用户不知道为什么他们应该按顺序处理所有内容,因为它会导致上述问题!

所以我认为发生的情况是,当处理与db的连接时,GC仍会在命令中检测到对连接的引用,这就是它推迟集合的原因,但是在处理命令之后它应该处理连接但它不会,至少我是这么看的:DI可能是错的。

所以请那些有GC和Mono经验的人为什么在MONO上这是一个问题而在Windows上我们使用dispose并不会增加任何问题。

谢谢你,最诚挚的问候!

0 个答案:

没有答案