Oracle.ManagedDataAccess库中可能的内存泄漏

时间:2018-01-26 04:14:04

标签: .net oracle memory memory-leaks oledb

我开始编写一个程序,将数据从oracle数据库复制到SQL Server数据库,并立即遇到内存问题。我正在使用Oracle.ManagedDataAccess库(nuget install命令:" install-package Oracle.ManagedDataAccess")。该库是版本4.122.1.0

这是我的功能:

    private static void LoadTable(TableToLoad table)
    {
        DataTable loadBuffer = null;
        //assume source is oracle for now.  assume destination is sql server
        using (OracleConnection conn = new OracleConnection(table.SourceConnectionString))
        {
            OracleDataReader reader = OracleCommands.GetDataReader(string.Format("select * from \"{0}\".\"{1}\"", table.SourceSchema, table.SourceTable),conn);
            bool foundData = reader.Read();
            if (loadBuffer == null)
            {
                loadBuffer = InitializeBuffer(reader);
            }

            int recordsAffected;

            while (foundData==true)
            {
                object[] currentRowValues = new object[reader.FieldCount];
                int valueCount = reader.GetValues(currentRowValues);
                loadBuffer.Rows.Add(currentRowValues);
                if (loadBuffer.Rows.Count >= 15000)
                {
                    SqlCommands.RunSqlCommandWithDataTableInput(string.Format("insert into {0}.{1} select * from @loadBufferTable", table.TargetSchema, table.TargetTable), table.TargetConnectionString, out recordsAffected, loadBuffer, "loadBufferTable");

                    loadBuffer.Dispose();
                    loadBuffer = null;
                    loadBuffer = InitializeBuffer(reader);
                }
                foundData = reader.Read();
            }

            if(loadBuffer.Rows.Count>0)
            {
                SqlCommands.RunSqlCommandWithDataTableInput(string.Format("insert into {0}.{1} select * from @loadBufferTable", table.TargetSchema, table.TargetTable), table.TargetConnectionString, out recordsAffected, loadBuffer, "loadBufferTable");

                loadBuffer.Dispose();
                loadBuffer = null;
            }

            reader.Close();
            reader.Dispose();
            reader = null;

        }
    }

当我运行它时,内存消耗刚刚开始,几分钟后我就会出现内存不足错误。我停止了这个过程并使用诊断工具来查看使用了这么多内存的内容。几乎所有的记忆都被成千上万的" OraBuf"由DataReader.Read方法创建的对象 Visual Studio Memory Usage Tool

我尝试解除分配并重新创建我用作插入批处理的缓冲区的DataTable对象,认为可能某种程度上DataTable持有对OraBuf对象的引用但是没有解决问题(我最初使用的是DataTable) .Clear()方法重置DataTable)。

为什么会发生这种情况(我该怎么做才能解决它?)

感谢您的帮助。

修改 我在Oracle中的测试表中有一个CLOB列。该问题似乎与读取CLOB值有关,因为在使用其他表时没有显示问题(没有OutOfMemoryException)。是否有更好的库来访问我应该使用的Oracle?

编辑2: 我还要提一下,我正在测试的表(CLOB列的那个)有大约290万条记录,它通常在行500,000和行1,500,000之间的某个地方失败(在内存故障之前的实际最低行数约为649,000并且最高约1,390,000)。

编辑3: 我尝试将这段代码配对以帮助识别问题,而另一条产生影响的是:

    int valueCount = reader.GetValues(currentRowValues);

我还尝试了一个版本,我一次只读取一列,在这种情况下,使用索引读取值会导致问题(仅在CLOB列上)。以下是备用版本中导致异常的行:

    newRow[columnIndex] = reader[columnIndex];

2 个答案:

答案 0 :(得分:0)

根据link,这是Oracle驱动程序中的LOB处理错误。

解决方法(取自here)是:

                    var dataValue = reader.GetOracleValue(i);  

                    if (dataValue != null)  
                    {  
                        // Test returned Type  
                        if (dataValue is OracleClob)  
                        {  
                            OracleClob oClob = dataValue as OracleClob;  
                            // Read text  
                            currentRowValues[i] = oClob.Value;  
                            oClob?.Close();  
                        }  
                        else if (dataValue is OracleBlob)  
                        {  
                            OracleBlob oBlob = dataValue as OracleBlob;  
                            // Read data  
                            currentRowValues[i] = oBlob.Value;  
                            oBlob?.Close();  
                        }  
                    }

答案 1 :(得分:0)

在批处理应用程序中读取300万行时,我在CLOB列上也遇到了同样的问题。当我将InitialLobFetchSize设置为-1时,似乎可以控制内存使用情况:

command.InitialLOBFetchSize = -1;