是否有可能编写的代码造成无法通过终止进程来修复的破坏?

本文关键字:进程 终止 有可能 代码 是否 | 更新日期: 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),你可能会发现结果文本文件被截断了。