And*_*ell 1 c# memory-leaks loops
我有一个程序在后台每5秒运行一些方法.但是每5秒钟它的物理内存使用量会增加16-20 Kb.通过评论代码段,我将其缩小到这个特定的部分是造成问题的原因.我在这里错过了什么来正确释放分配的内存?
主方法的循环段:
while (true)
{
listMessages = FetchAllMessages();
//Commented out other segments. Not causing memory increase
System.Threading.Thread.Sleep(5000);
}
Run Code Online (Sandbox Code Playgroud)
方法叫:
public static List<Message> FetchAllMessages()
{
try
{
using (Pop3Client client = new Pop3Client())
{
client.Connect("pop.gmail.com", 995, true);
client.Authenticate("removed", "removed");
int messageCount = client.GetMessageCount();
List<Message> allMessages = new List<Message>(messageCount);
for (int i = messageCount; i > 0; i--)
{
if (verifiedEmail.Contains(client.GetMessage(i).Headers.From.Address) || verifiedSms.Contains(client.GetMessage(i).Headers.From.Address))
{
string tempMessage = client.GetMessage(i).ToMailMessage().Body.ToLower();
if (tempMessage.Contains("cmd") && tempMessage.Contains("fin"))
{
allMessages.Add(client.GetMessage(i));
}
}
client.DeleteMessage(i);
}
client.Disconnect();
return allMessages;
}
}
catch (Exception ex)
{
return null;
}
}
Run Code Online (Sandbox Code Playgroud)
可能导致内存使用量稳步增加的一个原因是你要GetMessage多次调用.根据您的POP客户端的编写方式,每次都可以分配一个新的缓冲区,以便它可以从POP服务器下载消息.那个记忆当然会被收集起来,但你不必要地运用垃圾收集器.你的效率也很低.
您应该考虑将代码更改为以下内容:
for (int i = messageCount; i > 0; i--)
{
var msg = client.GetMessage(i);
if (verifiedEmail.Contains(msg.Headers.From.Address)
|| verifiedSms.Contains(msg.Headers.From.Address))
{
string tempMessage = msg.ToMailMessage().Body.ToLower();
if (tempMessage.Contains("cmd") && tempMessage.Contains("fin"))
{
allMessages.Add(msg);
}
}
client.DeleteMessage(i);
}
Run Code Online (Sandbox Code Playgroud)
因此,不是client.GetMessage(i)四次调用,而是只调用一次.
它还使代码更易于阅读.
也就是说,我认为你的"内存泄漏"可能只是GC在收集内存方面花费了很多时间.
另一件事.你有一个睡眠循环:
while (true)
{
listMessages = FetchAllMessages();
Thread.Sleep(5000);
}
Run Code Online (Sandbox Code Playgroud)
你正在占用一个花费大部分时间无所事事的线程.你最好创建一个间隔为5秒的计时器,如下所示:
System.Threading.Timer MailTimer; // declare at class scope
// Do this in your initialization
MailTimer = new Timer(MessageFetcher, null, 5000, -1);
Run Code Online (Sandbox Code Playgroud)
而你的MessageFetcher方法是:
void MessageFetcher(object state)
{
listMessages = FetchAllMessages();
// do that other stuff that you didn't show
// reset the timer so that it fires 5 seconds from now
MailTimer.Change(5000, -1);
}
Run Code Online (Sandbox Code Playgroud)
初始化创建一个单次计时器,在五秒钟内到期并调用MessageFetcher.当MessageFetcher完成时,它设置了一个定时器,使得邮件将另5秒内检查.你想这样做而不是设置一个周期性的间隔,因为你不希望定时器MessageFetcher在前一个滴答未完成处理时再次调用.
该MessageFetcher方法在池线程上执行.使用计时器可以防止你不得不一直保持一个线程,占用内存,而它什么也没做.