发现和有趣的问题: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个循环,Sqliteexception无法打开数据库文件
在开始时启动过程输出:
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相当高。
他们增加了每个打开连接到数据库,这意味着可能不会从内存中释放,因为它应该!
所以find困难的方式..什么解决问题是…改变这一点:
conn.Dispose(); cmd.Dispose();
至:
cmd.Dispose(); conn.Dispose();
因为我知道上面的代码不是书中的最佳实践,所以还是有很多用户不知道为什么他们应该把所有的东西都处理好,因为这会导致上面的问题!
所以我认为当处理与db的连接时,GC仍然检测到命令中连接的引用,这就是为什么它会延迟收集,但是在处理命令之后应该处理连接,但至less不会这就是我所看到的:DI可能是错的。
所以请任何人在GC和单声道经验为什么MONO这是一个问题,而在Windows内存不增加任何方式,我们使用处置,不会造成任何问题。
感谢你并致以真诚的问候!