這似乎是一個非常流行的問題/問題這些天,但我似乎無法找到解決問題的方法。內存泄漏在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