Handle Memory-Leaking COM EXE Servers on a remote machine
By Peter Bromberg
Working with EXE COM Servers (MapPoint.exe, Excel.exe, and others) can be a daunting task if you have a large amount of repetitive processing, say on a threadpool.
Often these babies will have a small memory leak eventually resulting in out of memory OS errors. If this happens on a remote server, you could be sunk, because most likely you will not be able to even remote into a frozen box.
All the tricks we've learned -- Marshal.ReleaseComObject, GC.Collect, etc. may not
work with these EXE babies. In addition, killing the COM Server process and starting
a new one may also not work.
I have to process many hundreds of thousands of SQL Server records
with one of these COM Servers, and the memory usage continues to grow over time.
I can't let one of these run overnight because the machine would likely be hobbled and completely unusable
by the next day. So I came up with a last-resort "brute force" technique
that seems ugly, but - it works!
What I do is count the number of
iterations, and every time the process clocks an even 10,000 (or whatever number
you have determined), I kill the COM Server, stop processing on the Threadpool,
and spin up a brand new instance of my same app, which starts a new COM Server
with a very low initial memory footprint. The original instance is exited gracefully.
In this manner, I can have my process running for days on end with no fear of memory problems. Whenever a new
instance starts, it automatically picks up at the next row in the SQL Server
table that has not yet been processed and carries on for the next 10,000 rows.
// This is at the end of my Threadpool callback method
// Each time through the loop in the threadpool callback, I check if counter
id mod 10000 = zero
if (id % 10000 == 0)
{
//we have passed 10,000 iterations, so...
Kill(id);
}
// This method kills off the COM server, stops processing, spawns a brand new instance,
and exits the original
private static void Kill( int id)
{
Console.WriteLine("Recycling at " + id.ToString());
ProcessUtil.KillProcess(); // kill off the COM Server EXE process that has been growing out of control
mre.Set();
// /stop threadpool processing
// start a brand new instance of this same exe process
System.Diagnostics.Process.Start(System.Environment.CurrentDirectory + @"\YourProgram.exe");
// exit the original gracefully
System.Environment.Exit(0);
// DONE!
}
//this is a utility class to kill all instances of a given process, e.g. "Excel"
public static class ProcessUtil
{
public static void KillProcess()
{
foreach (Process clsProcess in Process.GetProcesses())
{
if (clsProcess.ProcessName.StartsWith("YourExeComServerName"))
{
clsProcess.Kill();
Console.WriteLine("KILLED IT.");
}
}
}
}
Handle Memory-Leaking COM EXE Servers on a remote machine (991 Views)