Which means when Process.Start fails because "Not enough system resources"

I have a C # application that launches another executable using Process.Start()

.

In 99% of cases, this call works great. After the application has been running for quite some time, it Process.Start()

will exit with an error message:

Insufficient system resources exist to complete the requested service

      

Initially I thought it must be due to a memory leak in my program - I profiled it in some detail and found no leak there - the amount of memory would still be reasonable even if this message failed.

Immediately after such a crash, if I print some system statistics, it seems that I have over 600MB of free memory, plenty of disk space, and the CPU utilization is effectively 0%.

Is there another system resource that I haven't thought of? Am I running into memory limitation in a .NET VM?

Edit2:

I opened the application in SysInternals Process Explorer and it looks like I will be passing left and right handles:

Handles Used: 11,950,352 (!)
GDI Handles: 26
USER Handles: 22

      

What's odd is that the Win32 side of the pens seems very reasonable, but somehow my raw number of pens exploded waaaaay out of control. Any ideas that could cause the Handle to leak like this? Initially I was sure it was Process.Start (), but those would be USER handles, right?

Edit:

Here's an example of how I create a process:

var pInfo = new ProcessStartInfo(path, ClientStartArguments)
        {
            UseShellExecute = false,
            WorkingDirectory = workingDirectory
        };    
ClientProcess = Process.Start(pInfo);

      

Here is an example of how I kill the same process (later in the program after I communicated with the process):

Process[] clientProcesses = Process.GetProcessesByName(ClientProcessName);
if (clientProcesses.Length > 0)
{
     foreach (var clientProcess in clientProcesses.Where(
              clientProcess => clientProcess.HasExited == false))
     {
        clientProcess.Kill();
     }
}

      

+3


source to share


3 answers


The problem here is preserving the process handles. As we can see from the subsequent changes, you keep the reference to the process object returned by Process.Start (). As stated in the process documentation :

Like many Windows resources, a process is also identified by its handle, which may not be unique on the computer. Handle is a generic term for a resource identifier. The operating system continues to process the handle to the process, which is accessed through the Handle property of the Process component, even when the process exits. This way you can get the administrative information of the process such as ExitCode (usually either zero for success or non-zero error code) and ExitTime. Pens are an extremely valuable resource, which is why a pen leak is more virulent than a memory leak.



I especially like the use of the word virulent. You need to remove and release the link to "Process".

Also check out this great question and related answer: Not enough memory or not enough pens?

+4


source


Since the class Process

implements IDisposable

, it is good practice to properly dispose of it when you're done. In this case, it will prevent the handles from leaking.

using (var p = new Process())
{
    p.StartInfo = new ProcessStartInfo(@"C:\windows\notepad.exe");
    p.Start();
    p.WaitForExit();
}

      



If you call Process.Kill()

and the process is already complete, you get InvalidOperationException

.

+2


source


This is not an uncommon problem with such small programs. The problem is that you are using a lot of system resources but very little memory. You are not putting enough pressure on the garbage collection, so the collector never starts. Thus, finalized objects, wrappers for system descriptors such as Process and Thread, never complete.

Simply deleting the Process object after the process exits will take a long time to resolve the issue. But this may not completely solve, any threads that use the Process class, or you use yourself, consume 5 operating system descriptors. The Thread class does not have a Dispose () method. It should, but it is not, it is almost impossible to name it correctly.

The solution runs garbage collection on its own. Count the number of attempts to start the process. Every, say, the hundredth time call GC.Collect (). Keep track of the number of pens with Taskmgr.exe. Use View + Select Columns to add it. Fine tune the call to GC.Collect so that it doesn't increment, say 500.

+1


source







All Articles