是否有可能编写的代码造成无法通过终止进程来修复的破坏?
本文关键字:进程 终止 有可能 代码 是否 | 更新日期: 2023-09-27 17:53:15
这个问题多年来一直在我的脑海里。我要讲一点历史/背景。
当我在编程c++的时候,我对"内存泄漏"有很深刻的理解:你调用new X,然后调用delete X。如果你不多次执行第二部分,你会看到程序所消耗的内存无限增长。
但是,当你关闭应用程序并重新启动时,所有内容都将归零。由于这个原因,通过强制重启来修复内存泄漏是可行的(可能不是最好的解决方案)。
我模糊地意识到,当我做一些WinApi编程,这是可能搞砸,并开始一个"处理泄漏"。资源监视器向您显示了这一点,我认为是杀死程序并不能原谅您的错误代码的情况。我还以为你得重启呢。但事实是,我采取了额外的偏执狂来避免这些泄漏,而不是试图真正了解它们的根本原因。
在。net中,对象被自动计算引用计数,并且后台线程会清除分配给孤立对象所消耗的内存。但是仍然有一些东西暗示可能会搞砸,比如术语"非托管资源"。到目前为止,我一直保持自己感觉"安全",总是遵循我看到的模式,例如,如果我想查询SQL,我会先谷歌一下,找到类似的东西:
public DataTable GetData(SqlCommand cmd)
{
DataTable dt = new DataTable();
String strConnString
=System.Configuration.ConfigurationManager.ConnectionStrings["conString"].ConnectionString;
SqlConnection con = new SqlConnection(strConnString);
cmd.Connection = con;
SqlDataAdapter sda = new SqlDataAdapter();
cmd.CommandType = CommandType.Text;
try
{
con.Open();
sda.SelectCommand = cmd;
sda.Fill(dt);
}
catch
{
return dt;
}
finally
{
con.Close();
cmd.Dispose();
sda.Dispose();
}
return dt;
}
我的问题是我从来没有花时间去想"如果我没有关闭连接会怎么样?"-我只是使用复制/粘贴技术,然后继续。
像LinqPad这样的代码片段工具的出现让我再次思考这个问题,因为我经常尝试使用api,例如我刚刚运行了代码片段:
string qbConStr = @"DSN=QuickBooks Data;SERVER=QODBC;OptimizerDBFolder=%UserProfile%'QODBC Driver for QuickBooks'Optimizer;OptimizerAllowDirtyReads=N;SyncFromOtherTables=Y;IAppReadOnly=Y";
OdbcConnection connection = new OdbcConnection(qbConStr);
connection.Open();
connection.GetSchema();
我不想用"good form",因为,毕竟,这是一个片段,对吧?
问题:对吧?
我不知道如何导致句柄泄漏/无法修复的损坏,无法通过终止进程来修复-我确信这是可能的,但您需要尝试合理地努力做到这一点(未能关闭文件句柄的数据库连接不会导致这种情况-这些将由操作系统在进程终止时释放)。
仅供参考,而不是以这种方式使用try-catch
,你应该使用dispose
代替-在掩护下它做同样的事情,但结果更干净,更容易阅读:
public DataTable GetData(SqlCommand cmd)
{
DataTable dt = new DataTable();
string strConnString = ConfigurationManager.ConnectionStrings["conString"].ConnectionString;
using (SqlConnection con = new SqlConnection(strConnString))
{
cmd.Connection = con;
using (SqlDataAdapter sda = new SqlDataAdapter())
{
cmd.CommandType = CommandType.Text;
con.Open();
sda.SelectCommand = cmd;
sda.Fill(dt);
}
}
return dt;
}
你也应该避免捕获吞噬异常——如果上面的代码抛出了一个异常,最好由调用者来处理。此外,您应该将SqlCommand的处置留给调用者,因为他们将命令传递进来,并且可能想要重用它。
关于dispose
和一次性对象的最后一个注意事项-句柄和其他操作系统资源将在进程终止时被清理,但这与调用dispose方法不同,后者不会在进程终止时自动完成。这在某些情况下很重要,例如使用StreamWriter
向文件写入时。这个流是缓冲的,所以除非你调用Flush
(或者Dispose
,然后调用Flush
),你可能会发现结果文本文件被截断了。