Oracle8i Java Developer's Guide Release 3 (8.1.7) Part Number A83728-01 |
|
Aurora preserves the state of your Java program between calls by migrating all objects reachable from static variables into session space at the end of the call. Session space exists within the client's session to store static variables and objects that exist between calls. Aurora performs this migration operation at the end of every call, without any intervention by you.
This migration operation is a memory and performance consideration; thus, you should be aware of what you designate to exist between calls and keep the static variables and objects to a minimum. If you store objects in static variables needlessly, you impose an unnecessary burden on the memory manager to perform the migration and consume per-session resources. By limiting your static variables to only what is necessary, you help the memory manager and improve your server's performance.
To maximize the number of users who can execute your Java program at the same time, it is important to minimize the footprint of a session. In particular, to achieve maximum scalability, an inactive session should take up as little memory space as possible. A simple technique to minimize footprint is to release large data structures at the end of every call. You can lazily recreate many data structures when you need them again in another call. For this reason, the Aurora JVM has a mechanism for calling a specified Java method when a session is about to become inactive, such as at end-of-call time.
This mechanism is the EndOfCallRegistry
notification. It enables you to clear static variables at the end of the call and reinitialize the variables using a lazy initialization technique when the next call comes in. You should execute this only if you are concerned about the amount of storage you require the memory manager to store in between calls. It becomes a concern only for more complex stateful server applications you implement in Java.
The decision of whether to null-out data structures at end-of-call and then recreate them for each new call is a typical time and space trade-off. There is some extra time spent in recreating the structure, but you can save significant space by not holding on to the structure between calls. In addition, there is a time consideration because objects--especially large objects--are more expensive to access after they have been migrated to session space. The penalty results from the differences in representation of session, as opposed to call-space based objects.
Examples of data structures that are candidates for this type of optimization include:
You can register the static variables that you want cleared at the end of the call when the buffer, field, or data structure is created. Within the Oracle-specified oracle.aurora.memoryManager
.EndOfCallRegistry
class, the registerCallback
method takes in an object that implements a Callback
object. The registerCallback
object stores this object until the end of the call. When end-of-call occurs, Aurora invokes the act
method within all registered Callback
objects. The act
method within the Callback
object is implemented to clear the user-defined buffer, field, or data structure. Once cleared, the Callback
is removed from the registry.
The way you use the EndOfCallRegistry
depends on whether you are dealing with objects held in static fields or instance fields.
EndOfCallRegistry
to clear state associated with an entire class. In this case, the Callback
object should be held in a private static field. Any code that requires access to the cached data dropped between calls must invoke a method that lazily creates--or recreates--the cached data. The example below does the following:
Callback
object within a static field, thunk
.
Callback
object for end-of-call migration.
Callback.act
method to free up all static variables, including the Callback object itself.
createCachedField
, for lazily recreating the cache.
When the user creates the cache, the Callback
object is automatically registered within the getCachedField
method. At end-of-call, Aurora invokes the registered Callback.act
method, which frees the static memory.
import oracle.aurora.memoryManager.Callback; import oracle.aurora.memoryManager.EndOfCallRegistry; class Example { static Object cachedField = null;private static Callback thunk = null;
static void clearCachedField() { // clear out both the cached field, and the thunk so they don't // take up session space between calls cachedField = null; thunk = null; } private static Object getCachedField() { if (cachedField == null) { // save thunk in static field so it doesn't get reclaimed // by garbage collectorthunk = new Callback () {
public void act(Object obj) {
Example.clearCachedField();
}
}; // register thunk to clear cachedField at end-of-call.EndOfCallRegistry.registerCallback(thunk);
// finally, set cached field cachedField = createCachedField(); } return cachedField; } private static Object createCachedField() { .... } }
EndOfCallRegistry
to clear state in data structures held in instance fields. For example, when a state is associated with each instance of a class, each instance has a field that holds the cached state for the instance and fills in the cached field as necessary. You can access the cached field with a method that ensures the state is cached.
Callback
object.
Callback.act
method to free up the instance's fields.
Callback
object registers itself for end-of-call migration.
createCachedField
, for lazily recreating the cache.
When the user creates the cache, the Callback
object is automatically registered within the getCachedField
method. At end-of-call, Aurora invokes the registered Callback.act
method, which frees the cache.
This approach ensures that the lifetime of the Callback
object is identical to the lifetime of the instance, because they are the same object.
import oracle.aurora.memoryManager.Callback; import oracle.aurora.memoryManager.EndOfCallRegistry; class Example2implements
Callback { private Object cachedField = null; public voidact
(Object obj) { // clear cached field cachedField = null; obj = null; } // our accessor method private static Object getCachedField() { if (cachedField == null) { // if cachedField is not filled in then we need to // register self, and fill it in.EndOfCallRegistry.registerCallback(self);
cachedField = createCachedField(); } return cachedField; } private Object createCachedField() { .... } }
A weak table holds the registry of end-of-call callbacks. If either the Callback object or value are not reachable (see JLS section 12.6) from the Java program, they will both be dropped from the table. The use of a weak table to hold callbacks also means that registering a callback will not prevent the garbage collector from reclaiming that object. Therefore, you must hold on to the callback yourself if you need it--you cannot rely on the table holding it back.
You can find other ways in which end-of-call notification will be useful to your applications. The following sections give the details for methods within the EndOfCallRegistry
class and the Callback interface:
The registerCallback
method installs a Callback
object within a registry. At the end of the call, Aurora invokes the act
methods of all registered Callback
objects.
You can register your Callback
object by itself or with a value
object. If you need additional information stored within an object to be passed into act
, you can register this object within the value parameter.
public static void registerCallback(Callback thunk, Object value); public static void registerCallback(Callback thunk);
static void runCallbacks()
The JVM calls this method at end-of-call and calls act
for every Callback
object registered using registerCallback
. You should never call this method in your code. It is called at end-of-call, before object migration and before the last finalization step.
Interface oracle.aurora.memoryManager.Callback
Any object you want to register using EndOfCallRegistry.registerCallback
implements the Callback
interface. This interface can be useful in your application, where you require notification at end-of-call.
public void act(Object value)
You can implement any activity that you require to occur at the end of the call. Normally, this method will contain procedures for clearing any memory that would be saved to session space.
|
Copyright © 1996-2000, Oracle Corporation. All Rights Reserved. |
|