SQL Server CLR中是否有任何内存泄漏或一些错误?

时间:2014-10-27 18:57:48

标签: sql-server memory-leaks resultset sqldatareader sqlclr

有我的代码,这个方法抛出异常通常在多个线程调用它时,有时会抛出threadAbortException,有时抛出内存或内存被SQL Server收集,还有另一个用于锁定的类一个List,它存储了访问过的客户端信息,SQL Server通常会清除它或释放CLR程序集,我不知道为什么。如果您有CLR经验,能帮助我吗,谢谢。我的代码如下:

private static bool QueryResultSet(string value)
{
    if(string.IsNullOrEmpty(value))
    {
        return false;
    }

    int returnValue;
    bool result;

    if (!Int32.TryParse(value, out returnValue))
    {
        return false;
    }

    result = true;
    try
    {   
        using (SqlDataReader dr = SqlHelper.ExecuteReader(SqlHelper.connectionString,
            CommandType.Text,
            string.Format("SELECT {0} AS Result", returnValue)))
        {
            SqlContext.Pipe.Send(dr);
        }
    }
    catch (Exception ex)
    {
        _logger.Error(ex);
        result = false;
    }

    return result;
}

1 个答案:

答案 0 :(得分:0)

使用SqlHelper.ExecuteReader(conectionString...)时,默认情况下会出现内存泄漏。使用连接字符串而不是连接时的ExecuteReader()方法在设计上出现故障。由于Connection是在方法内部而不是在外部进行的,因此无法正确使用,因此在使用阅读器后无法手动关闭连接。因此,首先,在using语句中创建连接,然后将其传递给SqlHelper.ExecuteReader(_theConnection ..)方法。

以下是ApplicationBlocks.Data源中的相同函数:

    /// <summary>
    /// Execute a SqlCommand (that returns a resultset) against the database specified in the connection string 
    /// using the provided parameters.
    /// </summary>
    /// <remarks>
    /// e.g.:  
    ///  SqlDataReader dr = ExecuteReader(connString, CommandType.StoredProcedure, "GetOrders", new SqlParameter("@prodid", 24));
    /// </remarks>
    /// <param name="ConnectionString">a valid connection string for a SqlConnection</param>
    /// <param name="commandType">the CommandType (stored procedure, text, etc.)</param>
    /// <param name="commandText">the stored procedure name or T-SQL command</param>
    /// <param name="commandParameters">an array of SqlParamters used to execute the command</param>
    /// <returns>a SqlDataReader containing the resultset generated by the command</returns>
    public static SqlDataReader ExecuteReader(string ConnectionString, CommandType commandType, string commandText, params SqlParameter[] commandParameters)
    {
        //create & open a SqlConnection
        SqlConnection cn = new SqlConnection(ConnectionString);
        cn.Open();

        try
        {
            //call the private overload that takes an internally owned connection in place of the connection string
            return ExecuteReader(cn, null, commandType, commandText, commandParameters,SqlConnectionOwnership.Internal);
        }
        catch
        {
            //if we fail to return the SqlDatReader, we need to close the connection ourselves
            cn.Close();
            throw;
        }
    }

正如我们从上面的确切函数中可以看到的那样,他们正在创建该函数内部的连接,然后他们正在创建阅读器并将其返回。

......连接永远不会关闭。

如果我们使用此方法,则连接池最终会溢出,因为默认情况下此函数会产生泄漏。因此,请不要通过传递连接字符串来使用此功能。而是在外面打开一个连接,将它传递给SqlHelper.ExecuteReader(),用读取器做东西,关闭阅读器然后关闭连接。

查看功能的修改代码:

private static bool QueryResultSet(string value)
{
    if(string.IsNullOrEmpty(value))
    {
        return false;
    }

    int returnValue;
    bool result;

    if (!Int32.TryParse(value, out returnValue))
    {
        return false;
    }

    result = true;
    using (SqlConnection connection = new SqlConnection(SqlHelper.connectionString)) 
    {
        try
        {
            using (SqlDataReader dr = SqlHelper.ExecuteReader(connection,
                CommandType.Text,
                string.Format("SELECT {0} AS Result", returnValue)))
            {
                SqlContext.Pipe.Send(dr);
            }
        }
        catch (Exception ex)
        {
            _logger.Error(ex);
            result = false;
        }
        finally
        {
            // TODO: Here you can check if connection state is open before closing it
            conneciton.Close();
        }
    }
    return result;
}