Windows Service Memory Usage

N

nautonnier

I know my problem has been discussed ad nauseum but I still don't get it so
please bear with me.

I have written a service which performs some work against a database once a
day (usually in the wee hours of the morning). From the time the service
starts to the first time it hits the database its memory consumption is
about 6.9MB which is a figure I can live with. However, after it hits the
database for the first time its memory jumps to 15MB and stays there. Now,
I'm a realist so 15MB isn't all that bad. I'm just looking to make the
service as slim as possible. so I would like, after it's finished with its
work if the memory could go back down to ~7MB. I'm wondering if there's a
better way to get rid of my database objects than what I'm doing now. Here's
the relevant portion of my service:

public class MyService: System.ServiceProcess.ServiceBase
{
private string timeToWork = "02:00";
private string startupVar2 = "something else";
private string configFileName = "MyService.cfg";
private System.Timers.Timer timer1 = null;
private EventLog appLog = null;
private SqlConnection sqlConnection = null;
private SqlDataAdapter da = null;
private DataTable dt = null;

public ETSReminder()
{
this.ServiceName = "MyService";
this.CanStop = true;
this.AutoLog = false;

appLog = new EventLog();
appLog.Source = "MyService";
}

// OnStart method starts the timer and adds the Elapsed event
// OnStop closes or disposes the service objects (

private void timer1_Elapsed(object sender,
System.Timers.ElapsedEventArgs e)
{
if (DateTime.Now.TimeOfDay >
Convert.ToDateTime(timeToWork).TimeOfDay &&
DateTime.Now.TimeOfDay <
Convert.ToDateTime(timeToWork).AddMinutes(5.5).TimeOfDay)
{
DoWork();
}
}

private void DoWork()
{
try
{
ArrayList connectionStrings =
GetConnectionStrings(configFileName);
sqlConnection = new SqlConnection();

SqlCommand cmd1 = new SqlCommand("sproc1");
cmdCleanup.CommandType = CommandType.StoredProcedure;
cmdCleanup.Connection = sqlConnection;

SqlCommand cmd2 = new SqlCommand("sproc2");
cmdUserList.CommandType = CommandType.StoredProcedure;
cmdUserList.Connection = sqlConnection;

SqlCommand cmd3 = new SqlCommand("sproc3");
cmdReminderSent.CommandType = CommandType.StoredProcedure;
cmdReminderSent.Connection = sqlConnection;

foreach (string connectionString in connectionStrings)
{
sqlConnection.ConnectionString = connectionString;
sqlConnection.Open();

cmd1.ExecuteNonQuery();

da = new SqlDataAdapter(cmd2);
dt = new DataTable();
da.Fill(dt);

foreach (DataRow dr in dt.Rows)
{
// Does stuff including sending some email
cmd3.ExecuteNonQuery();
}

sqlConnection.Close();
}
}
catch
{
// Handle any exceptions
}
finally
{
dt.Dispose();
da.Dispose();
sqlConnection.Dispose();
}
}

}

---end code---

I have the database objects as class variables in case something hangs while
it's working, I can close the connection from my error handling routines.

I have even tried adding GC.Collect() after I dispose sqlConnection but that
doesn't seem to make the memory ever go down.

I have another more sinister problem in that each time the timer1_Elapsed
runs about 20K of memory is added that never goes away. Since this is a 24/7
service this could be an even bigger problem.

I have no ego over my code so if I'm doing something dumb please tell me.
Otherwise I would love to hear any ideas how I may solve my two memory
issues.

Thanks,
nautonnier
 
N

nautonnier

you know where it says "public ETSReminder()"? you should probably change
that in your head to "public MyService()" and forget you ever saw what it
was really called.<g>
 
G

Guest

Nautonnier,
if your service only needs to perform its action once per day, I believe you
would be far better off with a console Executable that gets kicked off at the
proper time via an entry in Task Scheduler.

In this manner, once it's done, it will exit cleanly and there will be no
memory consumption for the next 24 hours.
Peter

--
Co-founder, Eggheadcafe.com developer portal:
http://www.eggheadcafe.com
UnBlog:
http://petesbloggerama.blogspot.com
 
N

nautonnier

That's not a bad idea Peter, except that I have no control over what happens
in the client environment and Task Scheduler may not even be enabled. Thus,
it was decided to go with a service.

-nautonnier
 
W

Willy Denoyette [MVP]

Task scheduler itself is a service, if a user is allowed to disable the
scheduler, who will stop him to disable your service?
It's a bad idea to continuously waste precious resources for a service that
effectively does some work only once per 24 hours for about a few seconds.

Willy.


"nautonnier" <onTheLambFromAllThatSpam> wrote in message
| That's not a bad idea Peter, except that I have no control over what
happens
| in the client environment and Task Scheduler may not even be enabled.
Thus,
| it was decided to go with a service.
|
| -nautonnier
|
|
| | > Nautonnier,
| > if your service only needs to perform its action once per day, I believe
| you
| > would be far better off with a console Executable that gets kicked off
at
| the
| > proper time via an entry in Task Scheduler.
| >
| > In this manner, once it's done, it will exit cleanly and there will be
no
| > memory consumption for the next 24 hours.
| > Peter
| >
| > --
| > Co-founder, Eggheadcafe.com developer portal:
| > http://www.eggheadcafe.com
| > UnBlog:
| > http://petesbloggerama.blogspot.com
| >
| >
| >
| >
| > "nautonnier" wrote:
| >
| > > I know my problem has been discussed ad nauseum but I still don't get
it
| so
| > > please bear with me.
| > >
| > > I have written a service which performs some work against a database
| once a
| > > day (usually in the wee hours of the morning). From the time the
service
| > > starts to the first time it hits the database its memory consumption
is
| > > about 6.9MB which is a figure I can live with. However, after it hits
| the
| > > database for the first time its memory jumps to 15MB and stays there.
| Now,
| > > I'm a realist so 15MB isn't all that bad. I'm just looking to make the
| > > service as slim as possible. so I would like, after it's finished with
| its
| > > work if the memory could go back down to ~7MB. I'm wondering if
there's
| a
| > > better way to get rid of my database objects than what I'm doing now.
| Here's
| > > the relevant portion of my service:
| > >
| > > public class MyService: System.ServiceProcess.ServiceBase
| > > {
| > > private string timeToWork = "02:00";
| > > private string startupVar2 = "something else";
| > > private string configFileName = "MyService.cfg";
| > > private System.Timers.Timer timer1 = null;
| > > private EventLog appLog = null;
| > > private SqlConnection sqlConnection = null;
| > > private SqlDataAdapter da = null;
| > > private DataTable dt = null;
| > >
| > > public ETSReminder()
| > > {
| > > this.ServiceName = "MyService";
| > > this.CanStop = true;
| > > this.AutoLog = false;
| > >
| > > appLog = new EventLog();
| > > appLog.Source = "MyService";
| > > }
| > >
| > > // OnStart method starts the timer and adds the Elapsed event
| > > // OnStop closes or disposes the service objects (
| > >
| > > private void timer1_Elapsed(object sender,
| > > System.Timers.ElapsedEventArgs e)
| > > {
| > > if (DateTime.Now.TimeOfDay >
| > > Convert.ToDateTime(timeToWork).TimeOfDay &&
| > > DateTime.Now.TimeOfDay <
| > > Convert.ToDateTime(timeToWork).AddMinutes(5.5).TimeOfDay)
| > > {
| > > DoWork();
| > > }
| > > }
| > >
| > > private void DoWork()
| > > {
| > > try
| > > {
| > > ArrayList connectionStrings =
| > > GetConnectionStrings(configFileName);
| > > sqlConnection = new SqlConnection();
| > >
| > > SqlCommand cmd1 = new SqlCommand("sproc1");
| > > cmdCleanup.CommandType = CommandType.StoredProcedure;
| > > cmdCleanup.Connection = sqlConnection;
| > >
| > > SqlCommand cmd2 = new SqlCommand("sproc2");
| > > cmdUserList.CommandType = CommandType.StoredProcedure;
| > > cmdUserList.Connection = sqlConnection;
| > >
| > > SqlCommand cmd3 = new SqlCommand("sproc3");
| > > cmdReminderSent.CommandType = CommandType.StoredProcedure;
| > > cmdReminderSent.Connection = sqlConnection;
| > >
| > > foreach (string connectionString in connectionStrings)
| > > {
| > > sqlConnection.ConnectionString = connectionString;
| > > sqlConnection.Open();
| > >
| > > cmd1.ExecuteNonQuery();
| > >
| > > da = new SqlDataAdapter(cmd2);
| > > dt = new DataTable();
| > > da.Fill(dt);
| > >
| > > foreach (DataRow dr in dt.Rows)
| > > {
| > > // Does stuff including sending some email
| > > cmd3.ExecuteNonQuery();
| > > }
| > >
| > > sqlConnection.Close();
| > > }
| > > }
| > > catch
| > > {
| > > // Handle any exceptions
| > > }
| > > finally
| > > {
| > > dt.Dispose();
| > > da.Dispose();
| > > sqlConnection.Dispose();
| > > }
| > > }
| > >
| > > }
| > >
| > > ---end code---
| > >
| > > I have the database objects as class variables in case something hangs
| while
| > > it's working, I can close the connection from my error handling
| routines.
| > >
| > > I have even tried adding GC.Collect() after I dispose sqlConnection
but
| that
| > > doesn't seem to make the memory ever go down.
| > >
| > > I have another more sinister problem in that each time the
| timer1_Elapsed
| > > runs about 20K of memory is added that never goes away. Since this is
a
| 24/7
| > > service this could be an even bigger problem.
| > >
| > > I have no ego over my code so if I'm doing something dumb please tell
| me.
| > > Otherwise I would love to hear any ideas how I may solve my two memory
| > > issues.
| > >
| > > Thanks,
| > > nautonnier
| > >
| > >
| > >
|
|
 
N

nautonnier

My point was all this was discussed with the client and this was the way
they wanted to go.
 
N

nautonnier

So I guess my first pointed question is wouldn't the call to dispose of the
connection, dataadapter and datatable objects mark them so the GC reclaims
their memory and shouldn't that conceivably occur within 5 minutes? Would
this not also be true of the command objects once they went out of scope at
the end of DoWork()?

At this point I'm trying to understand things at a deeper level and
hopefully become a better programmer.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top