【问题标题】:Non-Static and Static method and class memory allocation非静态和静态方法和类内存分配
【发布时间】:2016-01-26 15:00:36
【问题描述】:

静态问题:

在我基于 C# 的应用程序中,我必须使用来自静态类的一些静态方法。这是我的代码的一部分:

        //Timer Event (interval: 100ms)
        private void OnTimedEvent2(object source, ElapsedEventArgs e)
        {
            try
            {
                //...

                DataUpdaterClass.Update("SomeString");

                //...
            }

            catch (Exception ex)
            {
                //...
            }

我的问题是,如果我在每个 TimerTick, 中调用 Update 方法,它是每次分配内存还是只分配一次?

非静态问题:

Timer 相同,但为非静态方法。

        static IPEndPoint MyIPEndPoint = new IPEndPoint(IPAddress.Parse("127.0.0.1"), 9999);
        static Socket MySocket = null;

        ////Timer Event (interval: 100ms)
        private void OnTimedEvent2(object source, ElapsedEventArgs e)
        {
            try
            {
                if (MySocket == null)
                {
                    MySocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
                    MySocket.Connect(MyIPEndPoint);
                }

                 //...
            }

            catch (Exception ex)
            {
                MySocket.Dispose();
                MySocket = null;
            }
        }

我的第二个问题是,如果我的程序抛出一个错误,那么我的Socket 会被释放并且以后不会使用任何内存吗?

非常感谢。

编辑:

感谢您的回答。我觉得我需要为您添加一些额外的信息。

我的应用程序是一个 Windows 服务,它从我们工厂的工业设备中收集有关产品重量的数据。所以它需要连续运行。现在我正在检查我的服务使用的内存,我发现它总是更大。它的增长非常缓慢,我看到 GC 完成了它的工作,但使用的内存仍在增长。我还发布了完整的Timer 事件和Update 方法。我希望你能帮助我。

类名、变量名、方法名都是匈牙利文,希望不会出问题。

定时器事件:

        static string Adat1 =static string IP1 = Convert.ToString(_3DESDekodoloClass.Decrypt(ConfigurationManager.AppSettings["merleg_1_IP"]));
        static int Port1 =Convert.ToInt32(_3DESDekodoloClass.Decrypt(ConfigurationManager.AppSettings["merleg_1_Port"]));
        static int Olvasott1 = 0;
        IPEndPoint Vegpont1 = new IPEndPoint(IPAddress.Parse(IP1), Port1);
        Socket Merleg1 = null;
        static byte[] Buffer1 = new byte[1024];

        //Starts in the OnStart() event.
        private void OnTimedEvent1(object source, ElapsedEventArgs e)
        {
            try
            {
                if (Merleg1 == null)
                {
                    Merleg1 = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
                    Merleg1.Connect(Vegpont1);
                }

                Olvasott1 = Merleg1.Receive(Buffer1);
                Adat1 = Encoding.ASCII.GetString(Buffer1, 0, Olvasott1);
                AdafeltoltoClass.Merleg_1_adatfeltolto(Adat1);
            }

            finally
            {
                if (Merleg1 != null)
                {
                    Merleg1.Dispose();
                }

                Merleg1 = null;
            }
        }

这是我的Update 方法:

        static AnritsuDataCollector fo_osztaly = new AnritsuDataCollector();

        static SqlDataAdapter sda_1 = new SqlDataAdapter();
        static SqlDataAdapter sda_2 = new SqlDataAdapter();

        static SqlDataAdapter sda_gauss_1 = new SqlDataAdapter();
        static SqlDataAdapter sda_gauss_2 = new SqlDataAdapter();

        //Adatok kinyerése a config fájlból dekódolás után.
        static string data_source = _3DESDekodoloClass.Decrypt(ConfigurationManager.AppSettings["data_source"]);
        static string initial_catalog = _3DESDekodoloClass.Decrypt(ConfigurationManager.AppSettings["initial_catalog"]);
        static string user_id = _3DESDekodoloClass.Decrypt(ConfigurationManager.AppSettings["user_id"]);
        static string password = _3DESDekodoloClass.Decrypt(ConfigurationManager.AppSettings["password"]);

        static string ProductId1 = "";
        static string RankCode1 = "";
        static string Suly1 = "";

        static string ProductId2 = "";
        static string RankCode2 = "";
        static string Suly2 = "";

        internal static void Merleg_1_adatfeltolto(string beerkezo)
        {
            try
            {
                //Az "con" SQL kapcsolat Pool-ba tétele.
                using (SqlConnection con = new SqlConnection(@"Data Source=" + data_source + ";Initial Catalog=" + initial_catalog + ";User ID=" + user_id + ";Password=" + password + ";"))
                {
                    //A kapcsolat megnyitása.
                    con.Open();

                    ProductId1 = beerkezo.Substring(4, 2);
                    RankCode1 = beerkezo.Substring(6, 1);
                    Suly1 = beerkezo.Substring(7, 5);

                    //Ha a suly tartalmaz szóközt.
                    if (Suly1.Contains(' '))
                    {
                        Suly1 = "00.00";
                    }

                    //SQL parancs az adatok feltöltéséhez.
                    using (sda_1.InsertCommand = new SqlCommand("INSERT INTO meresek (product_id, rank_code, merleg, suly, ido) VALUES (@product_id, @rank_code, @merleg, @suly, @ido)", con))
                    {

                        sda_1.InsertCommand.Parameters.Add("@product_id", SqlDbType.Int).Value = Convert.ToInt32(ProductId1);
                        sda_1.InsertCommand.Parameters.Add("@rank_code", SqlDbType.VarChar).Value = Convert.ToString(RankCode1);
                        sda_1.InsertCommand.Parameters.Add("@merleg", SqlDbType.Int).Value = 1;
                        sda_1.InsertCommand.Parameters.Add("@suly", SqlDbType.Float).Value = Convert.ToDouble(Suly1.Replace('.', ','));
                        sda_1.InsertCommand.Parameters.Add("@ido", SqlDbType.DateTime).Value = DateTime.Now;

                        //Az SQL utasítás elküldése a szervernek
                        sda_1.InsertCommand.ExecuteNonQuery();
                    }

                    using (sda_gauss_1.UpdateCommand = new SqlCommand("IF EXISTS(SELECT ROUND(suly,0) FROM gauss_statisztika_merleg_1 WHERE ROUND(suly,0) = @suly AND product_id = @product_id) BEGIN UPDATE gauss_statisztika_merleg_1 SET darab = darab + 1, utolso_meres = @utolso_meres WHERE ROUND(suly,0) = @suly AND product_id = @product_id END ELSE BEGIN INSERT INTO gauss_statisztika_merleg_1 VALUES(@product_id, @suly, 1, 1, @utolso_meres) END", con))
                    {
                        sda_gauss_1.UpdateCommand.Parameters.Add("@suly", SqlDbType.Float).Value = Math.Round(Convert.ToDouble(Suly1.Replace('.', ',')));
                        sda_gauss_1.UpdateCommand.Parameters.Add("@product_id", SqlDbType.Int).Value = Convert.ToInt32(ProductId1);
                        sda_gauss_1.UpdateCommand.Parameters.Add("@utolso_meres", SqlDbType.DateTime).Value = DateTime.Now;

                        sda_gauss_1.UpdateCommand.ExecuteNonQuery();
                    }
                }
            }

            catch (Exception ex)
            {
                fo_osztaly.Eventlog.WriteEntry(ex.Message);
            }
        }

【问题讨论】:

  • System.Net.Sockets.Socket 实现 IDisposable,使用 using
  • @Avsenev-Slava MySocket 在函数外部声明,并在每次调用函数时使用:这不是 using 的场景
  • @GianPaolo 无论如何,这不是一个好方法,也不是线程安全的。所以我会考虑这方面,不像这里的内存分配。

标签: c# sockets tcp timer


【解决方案1】:

静态问题: 调用已订阅的处理程序不会触发内存分配。代码已经在内存中。代码执行可能会触发内存分配。

非静态问题: 您无法保证何时从内存中删除对象 - 所以答案可能是。 您的示例有一个错误 - 您应该将“catch”更改为“finaly”并在处理之前检查 MySocket 是否不为空。

其他:根据您的问题,我认为您没有必要过多关注内存的有效使用。它是托管语言,大部分内存管理工作都是由 .NET 框架本身完成的

【讨论】:

    【解决方案2】:

    问题 #1: 你你的OnTimedEvent2你调用了一个静态方法:编译器不会为此分配任何内存,只是把代码调用该方法。 在方法中它是另一对袖子:如果它分配内存,它将为每个调用分配。但实际上,这取决于DataUpdaterClass.Update 的实现。

    问题 #2: 将 MySocket 变量设置为 null,从而删除对已分配套接字的所有引用,将允许垃圾收集器释放内存。 GC会根据自己的逻辑释放它。 所以是的,您可以考虑释放分配的套接字使用的内存。

    附带说明:不要过多关注内存管理。 .NET 实现了垃圾收集以将开发人员从内存管理问题中解放出来。 而且我从来没有发现 GC 不能正常工作的案例。

    在某些情况下,您必须关心软件分配和未释放的内存量,您的两种情况不在其中

    【讨论】:

      猜你喜欢
      • 2020-12-27
      • 2011-12-02
      • 1970-01-01
      • 1970-01-01
      • 2016-08-07
      • 2017-03-02
      • 1970-01-01
      • 1970-01-01
      • 2014-10-12
      相关资源
      最近更新 更多