Reputation: 3647
I am running the .net core application as windows service. However, after deployment on production I am facing memory leak issue, memory usage is continuously getting increased.
Below is my windows service,
public static class SendMailHostServiceExtensions
{
public static void RunAsSendMailService(this IWebHost host)
{
var webHostService = new SendMailHostService(host);
webHostService.ServiceName = "LMS.WinService.SendEmail";
ServiceBase.Run(webHostService);
}
}
and this is the class which is actually executing the service logic
public class SendMailHostService : WebHostService
{
public SendMailHostService(IWebHost host) : base(host)
{
}
protected override void OnStarted()
{
timer = new System.Timers.Timer(TimerInterval);
timer.Elapsed += OnElapsedTime;
timer.Enabled = true;
}
private void OnElapsedTime(object source, ElapsedEventArgs e)
{
try
{
StartSendMail();
}
catch (Exception ex)
{
Log(ex.ToString());
}
}
private void StartSendMail()
{
string connectionString = string.Empty;
bool isSentSuccess = false;
int errorCount = 0;
var context = new ApplicationDbContext();
try
{
Hashtable htFilePaths = new Hashtable();
{
List<LMS_Client> clientList = context.Clients.ToList();
if (clientList.Count > 0)
{
foreach (var item in clientList)
{
connectionString = string.Empty;
connectionString = "Server=" + item.ServerName + ";Database=" + item.DatabaseName + ";uid=" + item.UserName + ";password=" + item.Password;
strclientName = item.ClientName;
context = new ApplicationDbContext(connectionString);
List<LMS_MessageSend> result = context.MessageSend.Where(x => x.IsSent == false && x.ErrorCount < CheckErrorCount).ToList();
if (result.Count > 0)
{
foreach (var data in result)
{
strToName = data.ToName == null ? data.ToEmail : data.ToName;
strToAddress = data.ToEmail;
strFromNameAddressString = data.FromNameAddress;
strBody = data.BodyText;
strSubject = data.Subject;
strCC = data.CCEmail;
strBCC = data.BCCEmail;
if (CheckAttachment)
{
List<LMS_MessageSendAttachment> attachments = context.MessageSendAttachment.Where(x => x.MessageSendID == data.MessageSendID).ToList();
if (attachments.Count > 0)
{
foreach (var attachment in attachments)
{
strAttachmentPath = attachment.AttachmentPath == null ? string.Empty : attachment.AttachmentPath;
if (strAttachmentPath != string.Empty)
{
string[] fileArr = strAttachmentPath.Split(Convert.ToChar("|"));
if (fileArr.LongLength == 2)
{
htFilePaths.Add(MailAttachmentDrive + fileArr[0], MailAttachmentLocalDrive + fileArr[1]);
}
}
}
}
}
isSentSuccess = SendEmail(strToName, strToAddress, strFromNameAddressString, strSubject, strBody, htFilePaths, strCC, strBCC);
data.IsSent = isSentSuccess;
data.ErrorCount = isSentSuccess == false ? data.ErrorCount + 1 : 0;
data.SentDate = DateTime.Now;
}
context.UpdateRange(result);
context.SaveChanges();
}
}
}
}
}
catch (Exception ex)
{
isSentSuccess = false;
errorCount = 1;
Log(ex.ToString());
}
}
private bool SendEmail(string ToName, string ToEmail, string FromMail, string Subject, string BodyText, Hashtable htFilePaths, string CC, string BCC)
{
string[] addrArray = new string[0];
bool isSentSuccess = false;
IDictionaryEnumerator icKeys;
SmtpClient client = new SmtpClient();
try
{
using (MailMessage mm = new MailMessage())
{
ToEmail = ToEmail.Substring(0, 1) == ";" ? ToEmail.Substring(1, ToEmail.Length - 1) : ToEmail;
ToEmail = ToEmail.Substring(ToEmail.Length - 1, 1) == ";" ? ToEmail.Substring(0, ToEmail.Length - 1) : ToEmail;
addrArray = ToEmail.Split(';');
if (UseGoogleAuthentication)
{
mm.To.Add(new MailAddress("gmail address"));
}
else
{
foreach (string emailAddr in addrArray)
{
mm.To.Add(new MailAddress(emailAddr));
}
}
if (!string.IsNullOrEmpty(CC))
{
CC = CC.Substring(0, 1) == ";" ? CC.Substring(1, CC.Length - 1) : CC;
CC = CC.Substring(CC.Length - 1, 1) == ";" ? CC.Substring(0, CC.Length - 1) : CC;
addrArray = CC.Split(';');
foreach (string emailAddr in addrArray)
{
mm.CC.Add(new MailAddress(emailAddr.Trim()));
}
}
if (!string.IsNullOrEmpty(BCC))
{
BCC = BCC.Substring(0, 1) == ";" ? BCC.Substring(1, BCC.Length - 1) : BCC;
BCC = BCC.Substring(BCC.Length - 1, 1) == ";" ? BCC.Substring(0, BCC.Length - 1) : BCC;
addrArray = BCC.Split(';');
foreach (string emailAddr in addrArray)
{
mm.Bcc.Add(new MailAddress(emailAddr.Trim()));
}
}
mm.From = UseGoogleAuthentication == false ? mm.From = new MailAddress(FromMail) : new MailAddress("some gmail address");
mm.Subject = Subject;
mm.Body = BodyText;
mm.BodyEncoding = Encoding.UTF8;
mm.IsBodyHtml = true;
if (CheckAttachment)
{
if (htFilePaths != null && htFilePaths.Count > 0)
{
icKeys = htFilePaths.GetEnumerator();
while (icKeys.MoveNext())
{
if (icKeys.Key.ToString() != string.Empty && icKeys.Value.ToString() != string.Empty)
{
if (string.Compare(icKeys.Key.ToString(), icKeys.Value.ToString(), true) != 0)
{
File.Copy(icKeys.Key.ToString(), icKeys.Value.ToString(), true);
}
Attachment ma = new Attachment(icKeys.Value.ToString());
mm.Attachments.Add(ma);
}
}
}
}
if (UseGoogleAuthentication)
{
client.UseDefaultCredentials = false;
client.Host = "smtp.gmail.com";
client.Port = 587;
client.EnableSsl = true;
client.DeliveryMethod = SmtpDeliveryMethod.Network;
client.Credentials = new NetworkCredential("some gmail address", "gmail password");
client.Timeout = 20000;
}
else
{
client.Host = SMTPServer;
client.UseDefaultCredentials = false;
}
client.Send(mm);
isSentSuccess = true;
}
}
catch (Exception ex)
{
Log(ex.ToString());
}
finally
{
if (client != null) client.Dispose();
}
if (htFilePaths != null && htFilePaths.Count > 0)
{
icKeys = htFilePaths.GetEnumerator();
while (icKeys.MoveNext())
{
File.Delete(icKeys.Value.ToString());
}
}
return isSentSuccess;
}
}
After disposing the objects created still the memory usage is getting increased.
Any help on this appreciated !
Upvotes: 1
Views: 4965
Reputation: 8726
Identify all disposable managed objects that you instantiate (new
keyword) or obtain from a factory (disposable = object implements the IDisposable
interface). Then wrap them in a using block, like this:
using(var ctx = new ApplicationDbContext(connectionstring)
{
/* once ctx goes out of scope, it will automatically be disposed */
}
In the code you posted, ApplicationDbContext
and SmtpClient
are candidates for this. Whenever you assign another new instance to a variable that already holds a reference, that previous reference is leaked. So every reference needs to be disposed:
foreach(var hi in hashtables_can_be_foreached_too)
{
using(var o = new SomeDisposableObject())
{
/* code that works on o */
}
}
When dealing with memory leaks, you always need to be aware of some complexity:
Upvotes: 2