这似乎是一个非常流行的问题/问题这些天,但我似乎无法找到解决问题的方法。内存泄漏在C#Windows服务发送电子邮件
我在c#中创建了一个简单的Windows服务用于发送电子邮件。该应用程序工作很好,除了它的内存使用情况。该应用程序的前端是基于Web的,该服务通过在目录中创建的文本文件排队。阅读文本文件后,该服务从MS SQL数据库收集新闻简报信息和电子邮件地址,并开始每4秒发送一封电子邮件。在观察通过任务管理器运行的服务时,可以看到CPU每4秒钟使用一次,但立即降低。另一方面,记忆似乎并不是每一封电子邮件,而是每3-4封邮件增加50-75k。这将继续增加,直到发送所有电子邮件。我刚刚发出约。 2100封电子邮件,内存使用量高达100MB。我注意到的另一件事是,在发送完所有电子邮件之后,内存使用量将保持在此总和,直到我重新启动服务。当服务空闲时,内存运行在大约6500k。任何人有任何建议,我可以如何减少这些内存使用情况,并在完成邮件后处理掉?我的代码如下。任何帮助将不胜感激..
namespace NewsMailer
{
public partial class NewsMailer : ServiceBase
{
private FileSystemWatcher dirWatcher;
private static string filePath = @"E:\Intranets\Internal\Newsletter\EmailQueue";
private static string attachPath = @"E:\Intranets\Internal\Newsletter\Attachments";
private string newsType = String.Empty;
private string newsSubject = String.Empty;
private string newsContent = String.Empty;
private string userName = String.Empty;
private string newsAttachment = "";
private int newsID = 0;
private int emailSent = 0;
private int emailError = 0;
public NewsMailer()
{
InitializeComponent();
}
protected override void OnStart(string[] args)
{
dirWatcher = new FileSystemWatcher();
dirWatcher.Path = filePath;
dirWatcher.Created += new FileSystemEventHandler(ReadText);
dirWatcher.EnableRaisingEvents = true;
}
protected override void OnStop()
{
dirWatcher.EnableRaisingEvents = false;
dirWatcher.Dispose();
}
private void ClearVar()
{
newsType = String.Empty;
newsSubject = String.Empty;
newsContent = String.Empty;
userName = String.Empty;
newsAttachment = "";
newsID = 0;
emailSent = 0;
emailError = 0;
}
private void ReadText(object sender, FileSystemEventArgs e)
{
ClearVar();
SetLimits();
string txtFile = filePath + @"\QueueEmail.txt";
StreamReader sr = new StreamReader(txtFile);
string txtLine = String.Empty;
try
{
while ((txtLine = sr.ReadLine()) != null)
{
string[] lineCpl = txtLine.Split('§');
newsType = lineCpl[0];
userName = lineCpl[1];
newsID = Convert.ToInt32(lineCpl[2]);
}
}
catch (IOException ex)
{
SendExByMail("ReadText() IO Error", ex);
}
catch (Exception ex)
{
SendExByMail("ReadText() General Error", ex);
}
finally
{
sr.Close();
sr.Dispose();
}
GetNews();
}
[DllImport("kernel32.dll")]
public static extern bool SetProcessWorkingSetSize(IntPtr proc, int min, int max);
private void SetLimits()
{
GC.Collect();
GC.WaitForPendingFinalizers();
if (Environment.OSVersion.Platform == PlatformID.Win32NT)
SetProcessWorkingSetSize(Process.GetCurrentProcess().Handle, -1, -1);
}
private void DeleteText()
{
try
{
File.Delete(filePath + @"\QueueEmail.txt");
}
catch (IOException ex)
{
SendExByMail("DeleteText() IO Error", ex);
}
catch (Exception ex)
{
SendExByMail("DeleteText() General Error", ex);
}
}
private void GetNews()
{
string connectionString = ConfigurationManager.ConnectionStrings["contacts"].ConnectionString;
SqlConnection conn = new SqlConnection(connectionString);
string sqlSELECT = "SELECT newsSubject, newsContents, username, attachment FROM newsArchive " +
"WHERE ID = " + newsID;
SqlCommand comm = new SqlCommand(sqlSELECT, conn);
try
{
conn.Open();
using (SqlDataReader reader = comm.ExecuteReader())
{
while (reader.Read())
{
newsSubject = reader[0].ToString();
newsContent = reader[1].ToString();
userName = reader[2].ToString();
newsAttachment = reader[3].ToString();
}
reader.Dispose();
}
}
catch (SqlException ex)
{
SendExByMail("GetNews() SQL Error", ex);
}
catch (Exception ex)
{
SendExByMail("GetNews() General Error", ex);
}
finally
{
comm.Dispose();
conn.Dispose();
}
DeleteText();
GetAddress();
}
private void GetAddress()
{
string connectionString = ConfigurationManager.ConnectionStrings["contacts"].ConnectionString;
SqlConnection conn = new SqlConnection(connectionString);
string sqlSELECT = String.Empty;
if (newsType == "custom")
sqlSELECT = "SELECT DISTINCT email FROM custom";
else
sqlSELECT = "SELECT DISTINCT email FROM contactsMain WHERE queued = 'True'";
SqlCommand comm = new SqlCommand(sqlSELECT, conn);
try
{
conn.Open();
using (SqlDataReader reader = comm.ExecuteReader())
{
while (reader.Read())
{
try
{
if (CheckEmail(reader[0].ToString()) == true)
{
SendNews(reader[0].ToString());
Thread.Sleep(4000);
emailSent++;
}
else
{
SendInvalid(reader[0].ToString());
emailError++;
}
}
catch (SmtpException ex)
{
SendExByMail("NewsLetter Smtp Error", reader[0].ToString(), ex);
emailError++;
}
catch (Exception ex)
{
SendExByMail("Send NewsLetter General Error", reader[0].ToString(), ex);
emailError++;
}
finally
{
UnqueueEmail(reader[0].ToString());
}
}
reader.Dispose();
}
}
catch (SqlException ex)
{
SendExByMail("GetAddress() SQL Error", ex);
}
catch (Exception ex)
{
SendExByMail("GetAddress() General Error", ex);
}
finally
{
comm.Dispose();
conn.Dispose();
}
SendConfirmation();
}
private bool CheckEmail(string emailAddy)
{
bool returnValue = false;
string regExpress = @"^[\w-]+(?:\.[\w-]+)*@(?:[\w-]+\.)+[a-zA-Z]{2,7}$";
Match verifyE = Regex.Match(emailAddy, regExpress);
if (verifyE.Success)
returnValue = true;
return returnValue;
}
private void SendNews(string emailAddy)
{
string today = DateTime.Today.ToString("MMMM d, yyyy");
using (MailMessage message = new MailMessage())
{
SmtpClient smtpClient = new SmtpClient();
MailAddress fromAddress = new MailAddress("");
message.From = fromAddress;
message.To.Add(emailAddy);
message.Subject = newsSubject;
if (newsAttachment != "")
{
Attachment wusaAttach = new Attachment(attachPath + newsAttachment);
message.Attachments.Add(wusaAttach);
}
message.IsBodyHtml = true;
#region Message Body
message.Body = "";
#endregion
smtpClient.DeliveryMethod = SmtpDeliveryMethod.Network;
smtpClient.Host = "";
smtpClient.Credentials = new System.Net.NetworkCredential("");
smtpClient.Send(message);
smtpClient.ServicePoint.CloseConnectionGroup(smtpClient.ServicePoint.ConnectionName);
}
}
private void UnqueueEmail(string emailAddy)
{
string connectionString = ConfigurationManager.ConnectionStrings["contacts"].ConnectionString;
SqlConnection conn = new SqlConnection(connectionString);
string sqlStatement = String.Empty;
if (newsType == "custom")
sqlStatement = "UPDATE custom SET queued = 'False' WHERE email LIKE '" + emailAddy + "'";
else
sqlStatement = "UPDATE contactsMain SET queued = 'False' WHERE email LIKE '" + emailAddy + "'";
SqlCommand comm = new SqlCommand(sqlStatement, conn);
try
{
conn.Open();
comm.ExecuteNonQuery();
}
catch (SqlException ex)
{
SendExByMail("UnqueueEmail() SQL Error", ex);
}
catch (Exception ex)
{
SendExByMail("UnqueueEmail() General Error", ex);
}
finally
{
comm.Dispose();
conn.Dispose();
}
}
private void SendConfirmation()
{
SmtpClient smtpClient = new SmtpClient();
using (MailMessage message = new MailMessage())
{
MailAddress fromAddress = new MailAddress("");
MailAddress toAddress = new MailAddress();
message.From = fromAddress;
message.To.Add(toAddress);
//message.CC.Add(ccAddress);
message.Subject = "Your Newsletter Mailing Has Completed";
message.IsBodyHtml = true;
message.Body = "Total Emails Sent: " + emailSent +
"<br />Total Email Errors: " + emailError +
"<br />Contact regarding email errors if any were found";
smtpClient.Host = "";
smtpClient.Credentials = new System.Net.NetworkCredential("");
smtpClient.Send(message);
smtpClient.ServicePoint.CloseConnectionGroup(smtpClient.ServicePoint.ConnectionName);
}
ClearVar();
System.GC.Collect();
}
private void SendInvalid(string emailAddy)
{
SmtpClient smtpClient = new SmtpClient();
using (MailMessage message = new MailMessage())
{
MailAddress fromAddress = new MailAddress("");
MailAddress toAddress = new MailAddress("");
message.From = fromAddress;
message.To.Add(toAddress);
//message.CC.Add(ccAddress);
message.Subject = "Invalid Email Address";
message.IsBodyHtml = true;
message.Body = "An invalid email address has been found, please check the following " +
"email address:<br />" + emailAddy;
smtpClient.Host = "";
smtpClient.Credentials = new System.Net.NetworkCredential("");
smtpClient.Send(message);
smtpClient.ServicePoint.CloseConnectionGroup(smtpClient.ServicePoint.ConnectionName);
}
}
private void SendExByMail(string subject, Exception ex)
{
SmtpClient smtpClient = new SmtpClient();
using (MailMessage message = new MailMessage())
{
MailAddress fromAddress = new MailAddress("");
MailAddress toAddress = new MailAddress("");
message.From = fromAddress;
message.To.Add(toAddress);
//message.CC.Add(ccAddress);
message.Subject = subject;
message.IsBodyHtml = true;
message.Body = "An Error Has Occurred: <br />Exception: <br />" + ex.ToString();
smtpClient.Host = "";
smtpClient.Credentials = new System.Net.NetworkCredential("");
smtpClient.Send(message);
smtpClient.ServicePoint.CloseConnectionGroup(smtpClient.ServicePoint.ConnectionName);
}
}
private void SendExByMail(string subject, string body, Exception ex)
{
SmtpClient smtpClient = new SmtpClient();
using (MailMessage message = new MailMessage())
{
MailAddress fromAddress = new MailAddress("", "MailerService");
MailAddress toAddress = new MailAddress("");
message.From = fromAddress;
message.To.Add(toAddress);
//message.CC.Add(ccAddress);
message.Subject = subject;
message.IsBodyHtml = true;
message.Body = "An Error Has Occurred:<br /><br />" + body + "<br /><br />Exception: <br />" + ex.ToString();
smtpClient.Host = "";
smtpClient.Credentials = new System.Net.NetworkCredential("");
smtpClient.Send(message);
smtpClient.ServicePoint.CloseConnectionGroup(smtpClient.ServicePoint.ConnectionName);
}
}
}
}
MailMessage被处置,并且afaik附件也被处置。 – 2010-01-26 15:52:35
我了解处置附件的建议,但这是该应用程序的一项功能,从未使用过,因为它现在不会影响内存使用情况。 – user1017477 2010-01-26 16:05:33
刚刚在Reflector中打开,你是正确的:处置一个MailMessage也会调用任何附件上的Dispose。 – 2010-01-26 16:06:26