Enterprise Services (.NET 1.1) Performance Guidelines - Object Pooling
- J.D. Meier, Srinath Vasireddy, Ashish Babbar, and Alex Mackman
Return Objects to the Pool Promptly
Unmanaged COM+ objects return to the pool when their reference counts return to zero. Managed objects return to the pool only when garbage collected. There are several ways you can ensure an object is immediately returned to the pool and these vary depending on whether the object is configured for JIT activation:
- With JIT activation, use ASAP deactivation.
- Without JIT activation, the caller controls lifetime.
With JIT Activation, Use ASAP Deactivation
The context-maintained Done flag is initialized to false each time COM+ creates a new object in a context. If the Done flag is set to true when a method returns, COM+ deactivates and either destroys the object, or if object pooling is enabled, returns the object to the pool.
You can set the Done flag to true and force an object back to the pool in the following three ways:
- Use the AutoComplete attribute. Upon completion of a method marked with this attribute, the COM+ runtime either calls SetComplete or SetAbort, depending on whether the method generates an exception. Both methods set the Done flag in the object's context to true, which ensures that the object is returned to the pool. Use of the AutoComplete attribute is shown in the following code sample.
[ObjectPooling(MinPoolSize=0, MaxPoolSize=1)] [JustInTimeActivation()] public class YourClass : ServicedComponent { [AutoComplete] public void SomeMethod() { ... } ... }
Note Using this attribute is equivalent to selecting the Automatically deactivate this object when this method returns check box on a method's Properties dialog box in Component Services.
- Set ContextUtil.DeactivateOnReturn=true at the end of your method as shown in the following code sample.
public void SomeMethod() { // Do some work . . . // Make sure the object returns to the pool by setting DeacivateOnReturn ContextUtil.DeactivateOnReturn = true; }
- Call ContextUtil.SetComplete or ContextUtil.SetAbort at the end of your method. Both methods set the Done flag to true. Transactional components also use these methods to vote for the outcome of a transaction. SetComplete represents a vote for the transaction to commit while SetAbort votes for a transaction rollback.
Note Transaction outcome is dependent on the voting of all objects participating in the current transaction.
public void SomeMethod() { // Do some work . . . // Calling SetComplete (or SetAbort) sets the Done flag to true // which ensures the object is returned to the pool. ContextUtil.SetComplete(); }
Without JIT Activation, the Caller Controls Lifetime
If your pooled object is not configured for JIT activation, the object's caller must call Dispose and therefore controls the lifetime of the object. This is the only way Enterprise Services can know when it is safe to return the object to the pool.
Note Clients should always call Dispose on a disposable object regardless of the JIT activation setting. For more information, see "Resource Management" later in this chapter.
In C#, you can use the using keyword to ensure that Dispose is called.
// your pooled object's client code public void ClientMethodCallingPooledObject() { using (YourPooledType pooledObject = new YourPooledType()) { pooledObject.SomeMethod(); } // Dispose is automatically called here }
Monitor and Tune Pool Size
COM+ automatically adjusts the pool size to meet changing client loads. This behavior is automatic, but you can fine tune the behavior to optimize performance for your particular application. If the pool size is too large, you incur the overhead of populating the pool with an initialized set of objects, many of which remain redundant. Depending on the nature of the object, these objects might unnecessarily consume resources. Also, unless you manually start the application before the first client request is received, the first client takes the associated performance hit as the pool is populated with objects.
Preload Applications That Have Large Minimum Pool Sizes
When an application is started, it initializes the object pool and creates enough objects to satisfy the configured minimum pool size. By manually starting an application before the first client request is received, you eliminate the initial performance hit that the initial request would otherwise entail.
To automate application startup, you can use the following script code.
Dim oApplications 'As COMAdminCatalogCollection Dim oCatalog 'As COMAdminCatalog Dim oApp 'As COMAdminCatalogObject
Set oCatalog = CreateObject("ComAdmin.COMAdminCatalog") Set oApplications = oCatalog.GetCollection("Applications") oApplications.Populate
For Each oApp In oApplications If oApp.Name = "<Provide Your Server Application Name>" Then Call oCatalog.StartApplication(oApp.Name) Wscript.Echo oApp.Name + "Started..." End If Next
Note The automation script code applies only for server applications and not for library applications.
References
For more information about object pooling, see Microsoft Knowledge Base article 317336, "HOW TO: Use Enterprise Services Object Pooling in Visual Basic .NET," at http://support.microsoft.com/default.aspx?scid=kb;en-us;317336.