Just-in-Time Activation

JIT activation is another form of instance management. Whereas object pooling reduces the overhead involved with creating objects, JIT activation can reduce the overhead needed to maintain objects. To understand why JIT activation was developed, you need to consider the types of clients used in common distributed systems with COM.

Object pooling solves the problem that occurs when an object is expensive to create and must be created frequently. This problem typically appears with stateless client models. In the past, these problems were most commonly seen with ASP Web sites. Typically, when a client interacts with a Web page in ASP (or its successor, ASP.NET), a database object is created, used, and then disposed of. If the client performs several tasks (such as adding items to a shopping basket, configuring account information, and placing an order), these database objects might be re-created and disposed several times in a short period of time. This is where object pooling or connection pooling can dramatically reduce the load.

With rich clients, the situation was a little different. Typically, a rich client in a COM-based distributed application would create a reference to a remote database component (using DCOM) and potentially hold this reference for a long period of time. This is known as the "greedy client" problem, and it's a large part of the reason that JIT activation was invented.

With the greedy client problem, an object might be kept alive for a long period of time, wasting server resources. To compensate for this behavior, JIT activation automatically destroys the object at the end of each method call. The next time the client performs a method invocation, a new object is created to serve the request. Therefore, the client can maintain a permanent reference but no object is tied up at the server end.

JIT activation trades performance for scalability a common pattern in distributed applications. Re-creating an object each time the client needs it requires some work at the server side, and it adds time to the method request. However, the benefit is seen when the number of clients increases. Without JIT activation, greedy clients could starve a server of all its resources (typically memory and database connections), compromising the entire system. With JIT activation, the server footprint is lessened.

To mark a component for JIT activation, you need to add the <JustInTimeActivation> attribute to the class definition:

 <JustInTimeActivation()> _ Public Class JITTest 

By default, a JIT-activated object isn't automatically destroyed unless you explicitly state at the end of a method that it should be. You can do this in one of two ways. The first way is to add the <AutoComplete> attribute to the method, ensuring that the object is always deactivated when the method terminates, as follows:

 <AutoComplete()> _ Public Sub DoSomething()     ' Object is destroyed when this method ends. End Sub 

Another option is to use the ContextUtil.SetComplete method. This enables you to make the deactivation decision programmatically. If you determine that the object has important information in state, for example, you can refrain from calling SetComplete and keep it alive:

 Public Sub DoSomething()     If Data Is Nothing Then         ContextUtil.SetComplete()     End If End Sub 

Note

JIT activation is one rare case in which deterministic finalization returns to .NET programming. Because the serviced component deactivates itself, you can be sure it will be released after you call SetComplete or an <AutoComplete> method returns.


JIT-activated objects don't need to be stateless, but they lose all their state every time they are destroyed. Consider the serviced component in Listing 9-10.

Listing 9-10 A simple JIT class
 <JustInTimeActivation()> _ Public Class JITTest     Inherits ServicedComponent     Public ConstructorFlag As Boolean     Public Data As String     Public Sub New()         ConstructorFlag = True     End Sub     Public Sub DoSomething()         ' Test method.         ContextUtil.SetComplete()     End Sub End Class 

This object stores state in two member variables: ConstructorFlag and Data. However, this information is abandoned after every method call. Consider the following client code:

 Dim JIT As New TestComponent.JITTest() JIT.ConstructorFlag = False JIT.Data = "My String" ' After this method the object will be deactivated. JIT.DoSomething() Dim Status As String If JIT.ConstructorFlag     Status =  "The constructor executed again. "     Status &=  "The object was reconstructed." Else     Status = "The constructor did not execute." End If Status &= Environment.NewLine Status &= "Data is: " & JIT.Data MessageBox.Show(Status) 

Figure 9-11 shows the result of this code. Clearly, the JIT object was reconstructed and the data set by the client was lost.

Figure 9-11. Testing a JIT object

graphics/f09dp11.jpg

JIT-activated objects can override the Activate and Deactivate methods to serialize state to some sort of durable storage between method calls, but this isn't generally recommended. To tie an object with a specific state record, you need to use some sort of ticket system. For example, the object returns a ticket value to the client, and the client then needs to submit this ticket as an additional parameter for every method call, to allow the object to look up the saved state. The ticket can be a unique number or GUID. Chapter 13 describes ticket systems in detail.

JIT Activation and Object Pooling

JIT activation becomes particularly useful when combined with object pooling. This combination enables you to avoid having to re-create objects. Instead, objects are immediately released and returned to the pool at the end of every method call. In this case, a JIT object can also retain state. It's important to remember, however, that the only valid state you can use is information that is generic to all clients because a single client might receive a different instance of the object with each method call. That means it doesn't make sense for an object that uses JIT activation and object pooling to have a property procedure such as the one shown earlier in Listing 9-10.

Remember that with object pooling you need to override the CanBePooled method to specify whether the object should be destroyed or returned to the pool. (See Listing 9-11.) When you combine JIT activation and pooling, .NET first examines the context to determine whether the object should be deactivated. If you have called SetComplete or your method uses the <AutoComplete> attribute, .NET calls the CanBePooled method to determine whether the object should be destroyed or placed in the pool. If you have not called SetComplete or used the <AutoComplete> attribute, the object remains alive and is not pooled.

Listing 9-11 A simple pooled JIT class
 <JustInTimeActivation (), ObjectPooling()> _ Public Class JITTest     Inherits ServicedComponent     Public ConstructorFlag As Boolean     Public Sub New()         ConstructorFlag = True     End Sub     Public Sub DoSomething()         ' Test method.         ContextUtil.SetComplete()     End Sub     Protected Overrides Function CanBePooled() As Boolean         Return True     End Function End Class 

If you test the class shown in Listing 9-11, you'll discover that the ConstructorFlag is not set on subsequent method invocations. That's because the object is served from the pool, not re-created.

JIT Activation and .NET

For the .NET programmer, JIT activation is probably not as useful as object pooling because the greedy client problem is rare in the world of .NET. In fact, .NET tackles this problem by using a stateless model with XML Web services and single-call .NET Remoting objects. These objects follow the same activation pattern as JIT-activated objects in COM+: They are created at the start of a method call and are destroyed at the end, even though the client might maintain a reference over the lifetime of the application. In fact, the only way to hold a direct reference to a remote COM+ object in .NET is through a COM proxy that uses DCOM. This is already unlikely due to the complexity of DCOM!

Conversely, this means that pooling (either COM+ object pooling or ADO.NET connection pooling) is that much more important because objects are typically created and destroyed frequently in a typical .NET distributed system. JIT activation is still useful when you don't have any control over the client that is using the COM+ component but these situations are far less common in .NET than they were with COM-based applications.



Microsoft. NET Distributed Applications(c) Integrating XML Web Services and. NET Remoting
MicrosoftВ® .NET Distributed Applications: Integrating XML Web Services and .NET Remoting (Pro-Developer)
ISBN: 0735619336
EAN: 2147483647
Year: 2005
Pages: 174

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net