Oracle内存泄漏.当命令参数为OracleDbType.TimeStamp时,数据访问(OraOps11w)

本文关键字:数据 访问 OraOps11w TimeStamp OracleDbType 泄漏 内存 命令 参数 Oracle | 更新日期: 2023-09-27 17:49:39

执行ADO时。我注意到,在Oracle 11.2.0.3实例中包含OracleTimeStamp的非托管内存会增长,直到已使用的OracleConnection被处置。到目前为止,我只设法用OracleTimeStamp再现这种行为,当使用其他类型(Varchar2,…)时,一切都按预期工作。

下面是一个示例控制台应用程序,它导致非托管内存不断增长,直到处置连接:

internal class MemoryTestOracle
{
    private const string SpTestOracleTimeStamp = "SP_MEM_TEST_TIMESTAMP";
    private const string SpTestOracleTimeStampParam = "P_CONTENT_DATETIMEOFFSET";
    private const int StatementsPerLoop = 1000;
    private const string ConnectionString =
        "Data Source=YOURSERVER;Persist Security Info=True;User ID=YOURUSER;Password=YOURPASSWORD;Pooling=false";
    private static void Main(string[] args)
    {
        using (OracleConnection connection = new OracleConnection(ConnectionString))
        {
            Console.WriteLine("Start connect with {0}", typeof(OracleConnection).Assembly.ToString());
            connection.Open();
            for (int currentLoop = 0; true; currentLoop++)
            {
                OracleTimeStamp[] valuesDateTimeOffset = new OracleTimeStamp[StatementsPerLoop];
                Parallel.For(0, StatementsPerLoop,
                    current => { valuesDateTimeOffset[current] = new OracleTimeStamp(DateTime.Now); });
                Stopwatch stopExecution = Stopwatch.StartNew();
                using (OracleTransaction transaction = connection.BeginTransaction())
                {
                    using (OracleCommand command = new OracleCommand(SpTestOracleTimeStamp, connection))
                    {
                        command.Transaction = transaction;
                        command.CommandType = CommandType.StoredProcedure;
                        using (OracleParameter timeStampParameter = new OracleParameter())
                        {
                            timeStampParameter.OracleDbType = OracleDbType.TimeStamp;
                            timeStampParameter.Value = valuesDateTimeOffset;
                            timeStampParameter.Direction = ParameterDirection.Input;
                            timeStampParameter.ParameterName = SpTestOracleTimeStampParam;
                            command.Parameters.Add(timeStampParameter);
                            command.ArrayBindCount = valuesDateTimeOffset.Length;
                            command.ExecuteNonQuery();
                        }
                    }
                    transaction.Commit();
                }
                stopExecution.Stop();
                Console.WriteLine("Loop # {0} took {1} ms", currentLoop, stopExecution.ElapsedMilliseconds);
            }
        }
    }
}

在测试时,我使用了以下storedProcedure:

CREATE OR REPLACE PROCEDURE SP_MEM_TEST_TIMESTAMP (
   P_CONTENT_DATETIMEOFFSET TIMESTAMP
   )
IS
BEGIN
   NULL;
END;
/

这是Oracle的一个bug吗?DataAccess(4.112.3.0),安装的Oracle驱动程序或我在这里做错了什么(最有可能,但我不能弄清楚)?

非常感谢任何输入!

更新:增加使用/处置OracleParameter本身。与使用OracleParameter以及我认为我处置所有的一次性对象。问题仍然存在。

UPDATE 2:在大约15.000个循环(15.000.000 db执行)后,非托管内存大小约为150MB;即使DateTimeOffset值是在循环之外创建的(所以基本上所有循环都在相同的数据上运行),内存也会继续增长(尽管速度较慢)

UPDATE 3:到目前为止,我已经测试了上面的代码与Oracle的托管提供商以及-没有内存问题在那里。我还使用Devart的ADO提供程序运行了测试。在他们的一个版本(7.*)中,这个问题完全相同,在最近的版本中,它似乎已经修复了。

Oracle内存泄漏.当命令参数为OracleDbType.TimeStamp时,数据访问(OraOps11w)

尝试显式关闭并处理所有您正在使用的Oracle对象,包括oracleccommand, OracleTransaction和OracleParameter。

对于托管垃圾收集器来说,这些对象看起来并不重量级,但实际上它们在非托管端可能是如此。因此,最好的做法是在使用完所有内容后关闭并处理它们。