【问题标题】:C# - postgresql - memory leak over timeC# - postgresql - 随着时间的推移内存泄漏
【发布时间】:2019-01-25 10:51:11
【问题描述】:

问题:随着时间的推移内存泄漏(累积),最终达到 99% 的容量。

我有以下 C# 代码,它使用 while 循环不断地将数据推送到 PostgreSQL 数据库中。我真的很挣扎,因为我不是C# 程序员。我的主要语言是Python。我一直在尝试查找 C# 引用来解决我的问题,但失败了,因为我根本不懂很多语法。 C# 代码是我公司的其他人编写的,但他现在不可用。

代码如下:

var connString = "Host=x.x.x.x;Port=5432;Username=postgres;Password=password;Database=database";

using (var conn = new Npgsql.NpgsqlConnection(connString)){

    conn.Open();

    int ctr = 0;

    // Insert some data
    while(@tag.TerminateTimeScaleLoop == 100)
    {
        @Info.Trace("Pushed Data: PostGre A " + ctr.ToString());
        using (var cmd = new Npgsql.NpgsqlCommand())
        {
            cmd.Connection = conn;
            cmd.CommandText = "INSERT INTO TORQX VALUES (@r,@p)";
            cmd.Parameters.AddWithValue("r", System.DateTime.Now.ToUniversalTime());
            cmd.Parameters.AddWithValue("p", @Tag.RigData.Time.TORQX);
            cmd.ExecuteNonQuery();
            cmd.Parameters.Clear();


            cmd.CommandText = "INSERT INTO BLKPOS VALUES (@s,@t)";
            cmd.Parameters.AddWithValue("s", System.DateTime.Now.ToUniversalTime());
            cmd.Parameters.AddWithValue("t", @Tag.RigData.Time.BLKPOS);
            cmd.ExecuteNonQuery();
            cmd.Parameters.Clear();



           // @Info.Trace("Pushed Data: PostGre " + ctr.ToString());
        }

        ctr = ctr + 1;
    }
    @Info.Trace("Pushed Data: PostGre A Terminated");

代码一开始就成功建立了一个连接,并且整个过程只使用一个连接。它正确地将数据插入数据库。但是内存容量达到99%后,就不能很好的插入了。我能想到的问题的根源是这段代码不断地创建新对象,但在一次迭代完成后并没有清除该对象。谁能告诉我问题的根源在哪里并提供可能的解决方案?

++ 请理解我不是 C# 程序员...我对内存处理的概念不太熟悉。但我会尽力理解

【问题讨论】:

  • 你可能只是因为循环太快和太多而压倒了垃圾收集器。尝试在循环之外创建命令和参数,这样每次迭代只创建一个实例而不是一个实例。在循环内设置 CommandText 和参数值。

标签: c# postgresql memory memory-management memory-leaks


【解决方案1】:

您可以尝试以下方法。请注意,命令和参数的实例化发生在循环之外,而不是每次迭代。

我正在回收参数。因此,我使用的是Add(),而不是AddWithValue(),您必须为第二个参数填写数据库类型,并酌情考虑使用精度和比例参数。 这仅在两个命令使用相同的参数类型时才有效。您可以考虑创建两个命令,每个查询一个。

知道以@ 开头的变量名让我作为 C# 开发人员感到畏缩......

var connString = "Host=x.x.x.x;Port=5432;Username=postgres;Password=password;Database=database";

using (var conn = new Npgsql.NpgsqlConnection(connString))
{
    conn.Open();

    int ctr = 0;

    @Info.Trace("Pushed Data: PostGre A " + ctr.ToString());

    using (var cmd = new Npgsql.NpgsqlCommand())
    {
        cmd.Connection = conn;

        var par_1 = cmd.Parameters.Add("@p1", /*< appropriate datatype here >*/);
        var par_2 = cmd.Parameters.Add("@p2", /*< appropriate datatype here >*/);

        while(@tag.TerminateTimeScaleLoop == 100)
        {
            cmd.CommandText = "INSERT INTO TORQX VALUES (@p1,@p2)";
            par_1.Value = System.DateTime.Now.ToUniversalTime());
            par_2.Value = @Tag.RigData.Time.TORQX;

            cmd.ExecuteNonQuery();

            cmd.CommandText = "INSERT INTO BLKPOS VALUES (@p1,@p2)";

            par_1.Value = System.DateTime.Now.ToUniversalTime());
            par_2.Value = @Tag.RigData.Time.BLKPOS;

            cmd.ExecuteNonQuery();

            ctr = ctr + 1;
        }
    }
}
@Info.Trace("Pushed Data: PostGre A Terminated");

【讨论】:

  • 感谢您的回答。我有一个后续问题。 1. 为什么我必须用你的代码来定义数据类型?使用前面的代码,我看不到任何定义数据类型的代码,但它确实有效。 2.如果我必须定义数据类型,我应该如何定义它?我打印了par_1par_2 的数据类型,上面写着T.Kernel.Tags.AnalogDoubleSystem.DateTime。定义这些数据类型的 c# 代码是什么?
  • 我使用.GetType().ToString()打印了数据类型
  • 您不必定义数据类型,但这是一种很好的做法。我不知道 postgres 的细微差别,但省略数据类型可能会在 ms sql server 中出现性能和准确性问题。我不能告诉你如何定义类型,因为我不熟悉 postgres 提供者。我确定 API 已在线记录。
  • 嗨@Crowcoder 我知道这已经很多年了,我有类似的内存建立问题并试图找出原因。那么为什么 AddWithValue 会导致内存泄漏?他们不应该被垃圾收集吗?我正在使用 npgsqlconnection 和 dapper,你知道吗?
  • @Luminous_Dev AddWithValue 不会导致内存泄漏,我只是使用它,因为它是一个更好的实现。假设 postgres 提供程序使用良好的终结器正确实现,那么是的,即使您没有正确 dispose(),垃圾收集最终也会完成它的工作。但是仍然有可能压倒GC。不过,很可能您的问题与 sql 参数无关。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-06-23
  • 1970-01-01
  • 2013-08-10
  • 2011-03-07
  • 2014-12-11
相关资源
最近更新 更多