【问题标题】:C# Parallel.For and Oracle database access - memory exceptionC# Parallel.For 和 Oracle 数据库访问 - 内存异常
【发布时间】:2017-03-22 19:01:14
【问题描述】:

我正在编写一些代码,我想在 Parallel.For 循环内访问 Oracle 数据库。循环会运行几分钟,然后导致错误:

“试图读取或写入受保护的内存。这通常是 指示其他内存已损坏。”

没有内在的例外。在我的Parallel.For 循环中,我正在创建一个打开数据库连接作为本地对象。我的代码如下所示:

static void CheckSinglePath(Path p)
{    
     string sqlBase = "select * from table where hour = #HOUR#";
     Parallel.For (1, 24, i =>
     {        
            DBManager localdbm = new DBManager();                
            string sql = sqlBase;
            sql = sql.Replace("#HOUR#", i.ToString());
            OracleDataReader reader = db.GetData(sql);
            if (reader.Read())
            {
               //do some stuff
            }
            reader.Close();
     });
}

class DBManager
{
    OracleConnection conn;
    OracleCommand cmd;
    public DBManager()
    {
        string connStr = "blahblahblah;Connection Timeout=600;";
        conn = new OracleConnection(connStr);            
        conn.Open();
        cmd = conn.CreateCommand();
    }

    public OracleDataReader GetData(string sql)
    {
        cmd.CommandText = sql;
        return cmd.ExecuteReader();//EXCEPTION HERE!
    }        
}

我做错了什么?如何创建 24 个并行 Oracle 连接来处理数据?我猜这里发生了某种竞争条件或内存泄漏,我不完全理解,因为它似乎来自OracleConnection 对象内部。数据库连接不是线程安全的吗?我尝试更改连接字符串以使用连接池,但这并没有改变任何东西。

【问题讨论】:

    标签: c# multithreading oracle parallel-processing parallel-for


    【解决方案1】:

    内存问题总是由错误的资源使用引起。循环退出后,您没有正确释放连接。

    你需要实现IDisposable接口,然后你需要用using keyword这样的方式重写你的代码:

    // dispose the connection after command finished
    using (var localdbm = new DBManager())
    {            
        var sql = sqlBase;
        sql = sql.Replace("#HOUR#", i.ToString());
        using (var reader = db.GetData(sql))
        {
            if (reader.Read())
            {
               //do some stuff
            }
            // no need to close reader
            // as it's being disposed inside using directive
        }
    }
    

    【讨论】:

    • 不早点释放资源怎么会导致访问无效内存?如果任何没有 dispose 的东西会隐藏这样的错误,因为内存将保持有效时间更长。
    • @Voo OP 在一些之后遇到内存错误,所以非托管资源只会导致他内存损坏
    • 不释放内存怎么会导致访问释放的内存?如果你不处置非托管资源,你将耗尽资源,不会出现访问错误(除非我们用完内存并且非托管代码不检查 malloc 和 co 的返回值)
    • 在这种情况下,内存没有被释放,这就是问题所在。只有 托管 资源被释放,非托管 保留在内存中。一段时间后,基本上没有空间来存储新的连接了。
    • 谢谢,我今天早上尝试了新代码,它已经运行了几个小时,没有任何异常。谢谢!!
    猜你喜欢
    • 2015-03-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多