C# 防止计时器在控制台应用程序中被垃圾收集
总之,我正在监视outlook收件箱中的一些电子邮件,并根据内容进行分析。我通过运行控制台应用程序并触发计时器来实现这一点,如下所示。问题是这会在一段时间后被垃圾收集,我必须手动重新启动应用程序。我无法在windows服务中运行此操作,因为调用Outlook api时遇到一些权限问题。请看下面我的代码 我尝试对计时器对象执行GC.SuppressFinalize()、GC.KeepAlive(),但没有效果C# 防止计时器在控制台应用程序中被垃圾收集,c#,timer,garbage-collection,console-application,C#,Timer,Garbage Collection,Console Application,总之,我正在监视outlook收件箱中的一些电子邮件,并根据内容进行分析。我通过运行控制台应用程序并触发计时器来实现这一点,如下所示。问题是这会在一段时间后被垃圾收集,我必须手动重新启动应用程序。我无法在windows服务中运行此操作,因为调用Outlook api时遇到一些权限问题。请看下面我的代码 我尝试对计时器对象执行GC.SuppressFinalize()、GC.KeepAlive(),但没有效果 class Program { private stati
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);
}
在示例应用程序的范围内,
计时器
未被垃圾收集,因此您一定遇到了另一个错误。另外,请参阅我下面关于GC.SuppressFinalize
的说明和示例,因为您所暗示的和它所做的是两件不同的事情
循环而非计时器
只是一个建议:当使用计时器
并且已运行
事件调用计时器停止,然后在完成后再次启动时,这是一个迹象,您需要使用线程等待来运行一个简单的循环
由于这是一个控制台应用程序,并且不需要其他线程,因此我将发布一个简单的循环示例,在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);
}
}
}
GC.com信息
而且,GC.SuppressFinalize
与垃圾收集没有任何关系;它只是告诉垃圾收集器,在收集时,不要在对象上运行终结器(C#中的析构函数方法)。当有已处理的项目并且您不想复制工作时,这非常有用。。。例如,如果您的对象是IDisposable
,并且您将Dispose
方法放置在析构函数中,并且用户在使用时正确地处理了它,那么您可能希望跳过析构函数。下面是一个正确使用GC.SuppressFinalize
的示例
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.
}
GC.com示例
这里有一个控制台应用程序,演示了工作中的GC.SuppressFinalize
。我使2个IDisposable
对象。第一个我用using
语句正确地处理了,第二个我没有。一旦它们超出范围,就要进行垃圾收集。我故意调用垃圾收集器,并等待调用所有终结器,以便立即看到结果
请注意,disposed对象不调用终结器,而未disposed对象调用终结器(这反过来调用dispose…,这是实现它的正确方法)
输出:
Testing Disposable-Test
Disposed Disposable-Test
Testing Finalizing-Test
Finalized Finalizing-Test
Disposed Finalizing-Test
是什么让你认为计时器是GCd?每次触发回拨时,我都会将当前时间写入控制台。2-3分钟后,它将在当前时间停止向控制台写入。这让我觉得这是gcd,这不是GC的工作方式,它不会随机清除变量。一定是发生了什么事情阻止了你的代码运行。除了在我上面发布的代码中添加两个数字之外,我没有任何其他逻辑,我也没有看到从代码中抛出任何其他异常。不过,这段代码将永远运行。有一个问题,你只需要在finally块中输入time start,否则你会多次调用它。每次我看到
while(true)
我的强迫症发作并想要改变it@TheGeneral别担心,它被编译成一个简单的草书循环,没有测试条件,这是最简单的方法。如果你不喜欢它,那么就不要进入固件开发lol。同样,这是基于问题中提供的示例。这比使用计时器更高效,资源消耗更少,而且管理起来也更容易。有一点不同,就是您的解决方案将无限期运行,而OPs将在按下enter键时终止。我不清楚这种差异对OP是否重要。@AdamG我会告诉你的。我将用适当的循环更新它并读取。
Testing Disposable-Test
Disposed Disposable-Test
Testing Finalizing-Test
Finalized Finalizing-Test
Disposed Finalizing-Test