Enterprise Services (.NET 1.1) Performance Guidelines - Resource Management
- J.D. Meier, Srinath Vasireddy, Ashish Babbar, and Alex Mackman
Optimize Idle Time Management for Server Applications
COM+ shuts down the host process (Dllhost.exe) after a configured period of inactivity (the idle time) from any client. By default, the process stays in memory for three minutes if there are no clients using the application. To optimize idle time management:
- Consider increasing the idle time if clients tend to access components in short, sharp intervals in between lengthy periods of idle time. This will reduce the number of process restarts.
- If your application contains a pool of objects, leave the process running idle to avoid having to repopulate the object pool. If you expect your component to be called every ten minutes, increase the idle time to a slightly longer time. For example, set it to twelve minutes.
To configure the idle time, use the Advanced page of the application's Properties dialog box in Component Services. Values in the range 1–1440 minutes are supported.
Always Call Dispose
Client code that calls serviced components must always call the object's Dispose method as soon as it is finished using it. Setting the object reference to null or Nothing is not adequate. If you do not call Dispose, unmanaged resources must go through finalization which is less efficient and more resource intensive. Clients that do not call Dispose can cause activity deadlock in multithreaded applications due to the asynchronous cleanup of object references. If you do not call Dispose on pooled objects that do not use JIT activation, the pooled objects are not returned to the pool until they go through finalization and garbage collection. By calling Dispose, you efficiently release the unmanaged resources (such as COM objects) used by the serviced component and reduce memory utilization.
Calling Dispose
For class methods, you can simply call Dispose as shown in the following sample.
ComPlusLibrary comLib = new ComPlusLibrary(); comLib.Dispose();
For interface methods, you need to cast to IDisposable as shown in the following sample:
ServicedComp.ICom comLib = new ServicedComp.ComPlusLibrary(); // comLib.Dispose(); // Dispose not available when using the interface ((IDisposable)comlib).Dispose(); // Cast to IDisposable
If your client code does not call Dispose, one workaround is to use the DisableAsyncFinalization registry setting, but with negative consequences as described later in this chapter.
References
For more information about calling Dispose and releasing serviced components, see the following " Knowledge Base articles:
- 327443, "BUG: Multithreaded Applications Can Deadlock Because of Asynchronous Cleanup," at http://support.microsoft.com/default.aspx?scid=kb;en-us;327443.
- 312118, "The system memory usage and the handle counts increase more than you may expect when your application contains components that are derived from the System.EnterpriseServices.ServicedComponent class," at http://support.microsoft.com/default.aspx?scid=kb;en-us;312118.
- 318000, "FIX: Various Problems When You Call Transactional COM+ Components from ASP.NET,",at http://support.microsoft.com/default.aspx?scid=kb;en-us;318000.
DisableAsyncFinalization Registry Setting
If your managed client code does not call Dispose to release managed serviced components and you cannot change the client source code, as a last resort you can consider using the DisableAsyncFinalization registry key. This key prevents the serviced component infrastructure from co-opting user threads to help out with cleanup (leaving all the work to the finalizer thread).
To enable this feature, create the following registry key.
HKLM\Software\Microsoft\COM3\System.EnterpriseServices DisableAsyncFinalization = DWORD(0x1)
If You Call COM Components, Consider Calling ReleaseComObject
Consider calling ReleaseComObject if you call COM components. Examples include hosting COM objects in COM+ and calling them from Enterprise Services or calling them directly from a managed client, such as ASP.NET. Marshal.ReleaseComObject helps release the COM object as soon as possible. Under load, garbage collection (and finalization) might not occur soon enough and performance might suffer.
ReleaseComObject decrements the reference count of the RCW, which itself maintains a reference count on the underlying COM object. When the RCW's internal reference count goes to zero, the underlying COM object is released.
Calling ReleaseComObject
Consider the following scenarios where you might need to call ReleaseComObject:
- ASP.NET calling a COM component hosted in unmanaged COM+. The ASP.NET code should call ReleaseComObject when it has finished using the component.
- ASP.NET calling a serviced component that wraps and internally calls a COM component. In this case, you should implement Dispose in your serviced component and your Dispose method should call ReleaseComObject. The ASP.NET code should call your serviced component's Dispose method.
- Using a Queued Component recorder proxy or an LCE event class. In both cases, you are invoking unmanaged COM+ code.
Note If you call ReleaseComObject before all clients have finished using the COM object, an exception will be generated, if the object is subsequently accessed.
Marshal.Release
Calling the Marshal.Release method is unnecessary unless you manually manage object lifetime using Marshal.AddRef. It is also applicable when you call Marshal.GetComInterfaceForObject, Marshal.GetIUnknownForObject, or Marshal.GetIDispatchForObject to obtain an IUnknown interface pointer.
Summary of Dispose, ReleaseComObject, and Release Guidelines
You should only call ReleaseComObject where your managed code references an unmanaged COM+ component. In this instance, the unmanaged COM+ component will not provide a Dispose method. In cases where managed client code references a managed serviced component, the client code can and should call Dispose to force the release of unmanaged resources because all managed serviced components implement IDisposable. Table 8.4 summarizes when you need to call ReleaseComObject.
Client |
Server |
Call Dispose |
Call ReleaseComObject |
Call IUnknown Release |
Managed |
Managed component using ES |
Yes |
No |
No |
Managed |
Unmanaged component using COM+ |
No |
Yes |
No |
Unmanaged |
Managed component using ES |
Yes |
No |
Yes |
Unmanaged |
Unmanaged component using COM+ |
No |
No |
Yes |
Table 8.4 When to Call Dispose, ReleaseComObject, and IUnknown.Release
Note that unmanaged code should always call IUnknown.Release. If unmanaged code references a managed component using Enterprise Services, it should also first call Dispose on the COM Callable Wrapper (CCW) through which it communicates with the managed object. If unmanaged code references an unmanaged COM+ component, it simply calls IUnknown.Release.
The following are general guidelines:
- Cast to IDisposable. If the call is successful, call Dispose.
- Cast to Marshal. If the call is successful, call ReleaseComObject.