代码之家  ›  专栏  ›  技术社区  ›  randow_user_1234

防止计时器在控制台应用程序中被垃圾收集

  •  0
  • randow_user_1234  · 技术社区  · 6 年前

    总之,我正在监视outlook收件箱中的一些电子邮件和基于内容的分析。我通过运行控制台应用程序并触发计时器来实现这一点,如下所示。问题是这会在一段时间后被垃圾收集,我必须手动重新启动应用程序。我无法在windows服务中运行此操作,因为调用Outlook api时遇到一些权限问题。请参阅下面的我的代码

    我试着做一个GC。SuppressFinalize(),GC。计时器对象上的KeepAlive(),但无效。

        class Program
        {
           private static System.Timers.Timer _timer = new System.Timers.Timer();
           static void Main(string[] args)
            {
    
    
                _timer.Interval = 10000;            
                _timer.Start();
                _timer.Elapsed += Timer_Elapsed1;
    
                Console.ReadLine();
            }
        }
    
    
            private static void Timer_Elapsed1(object sender, System.Timers.ElapsedEventArgs e)
            {
                try
                {
                    _timer.Stop();                
                    AddNumbers(2, 2);
                    Console.WriteLine("The current time now is :{0}", DateTime.Now.ToString());
                    GC.SuppressFinalize(_timer);                
                    _timer.Start();
    
                }
                catch (Exception ex)
                {
                    _timer.Start();
                    Console.WriteLine("Timer restarted from exception");
                }
                finally
                {
                    _timer.Start();
                }
    
            }
    private static void AddNumbers(int x, int y)
            {
                var sum = x + y;
                Console.WriteLine(sum);
            }
    
    1 回复  |  直到 6 年前
        1
  •  0
  •   Michael Puckett II    6 年前

    在示例应用程序的范围内 Timer 未被垃圾收集,因此您一定遇到了另一个错误。另外,请参阅我下面关于 GC.SuppressFinalize 因为你所暗示的和它所做的是两件不同的事情。

    循环代替计时器

    只是一个建议:当使用 计时器 以及 Elapsed 事件调用计时器停止,然后在完成后再次启动。这表明您需要使用线程等待来运行一个简单的循环。

    由于这是一个控制台应用程序,并且不需要其他线程,因此我将发布一个简单的循环示例,在IMO中,该示例将更高效、更易于管理。

    using System;
    using System.Threading;
    
    namespace Question_Answer_Console_App
    {
        class Program
        {
            private const int SleepTimeMS = 10000;
            static void Main(string[] args)
            {
                ThreadPool.QueueUserWorkItem(new WaitCallback((state) =>
                {
                    while (true)
                    {
                        Thread.Sleep(SleepTimeMS);
                        AddNumbers(2, 2);
                        Console.WriteLine("The current time now is :{0}", DateTime.Now.ToString());
                    }
                }));
    
                Console.Read();
            }
    
            private static void AddNumbers(int x, int y)
            {
                var sum = x + y;
                Console.WriteLine(sum);
            }
        }
    }
    

    总承包商。SuppressFinalize信息

    而且 总承包商。抑制最终确定 与垃圾收集无关;它只是告诉垃圾收集器,在收集时,不要在对象上运行终结器(C#中的析构函数方法)。当有已处理的项目并且您不想复制工作时,这非常有用。。。例如,如果您的对象是 IDisposable ,然后您将 Dispose 方法,并且用户在使用时正确地处理它,那么您可能希望跳过析构函数。下面是使用 总承包商。抑制最终确定 正确地

    public class SomethingDisposable : IDisposable
    {
        public void Dispose()
        {
            //Dispose of some unmanaged resources or something.
            GC.SuppressFinalize(this); //We can safely skip the Destructor method (Finalizer)
        }
    
        ~SomethingDisposable() => Dispose(); //Just incase the object is garbage collected and never properly disposed.
    }
    

    总承包商。SuppressFinalize示例

    这是一个控制台应用程序,演示了 总承包商。抑制最终确定 在工作中。我做2 IDisposable可识别 对象。第一次我用 using 语句和第二个“我不知道”。一旦它们超出范围,就会进行垃圾收集。我有意调用垃圾收集器,并等待调用所有终结器,以便立即看到结果。

    请注意,disposed对象不调用终结器,而未disposed的对象调用终结器(这反过来又调用dispose…这是实现它的正确方法)

    using System;
    
    namespace Question_Answer_Console_App
    {
        class Program
        {
            private const string DisposableTestId = "Disposable-Test";
            private const string FinalizingTestId = "Finalizing-Test";
    
            static void Main(string[] args)
            {
                TestDisposing();
                Console.WriteLine();
                TestFinalizing();
    
                GC.Collect();
                GC.WaitForPendingFinalizers();
                Console.Read();
            }
    
            private static void TestDisposing()
            {
                using (var disposingTest = new TestSuppressFinalize(DisposableTestId))
                    PrintTesting(disposingTest);
            }
    
            private static void TestFinalizing()
            {
                var finalizingTest = new TestSuppressFinalize(FinalizingTestId);
                PrintTesting(finalizingTest);
            }
    
            private static void PrintTesting(TestSuppressFinalize finalizingTest)
                => Console.WriteLine($"Testing {finalizingTest.TestId.ToString()}");
        }
    
        public class TestSuppressFinalize : IDisposable
        {
            public TestSuppressFinalize(string testId) => TestId = testId;
            public string TestId { get; }
    
            public void Dispose()
            {
                Console.WriteLine($"Disposed {TestId.ToString()}");
                GC.SuppressFinalize(this); 
            }
    
            ~TestSuppressFinalize()
            {
                Console.WriteLine($"Finalized {TestId.ToString()}");
                Dispose();
            }
        }
    }
    

    输出:

    Testing Disposable-Test
    Disposed Disposable-Test
    
    Testing Finalizing-Test
    Finalized Finalizing-Test
    Disposed Finalizing-Test