Challenges in Developing a Scalable Java Environment with Oracle8I
- Challenges in Developing a Scalable Java Environment with Oracle8I
- Speed of Execution
It can be quite difficult to write reliable and scalable multithreaded Java applications. Megh Thakkar discusses the issues that developers must tackle when trying to improve scalability in e-commerce applications.
One of the key features of the Java language is its support of multithreading. However, it is still quite difficult to write reliable and scalable multithreaded Java applications. This article discusses the issues that developers must tackle when trying to improve scalability in e-commerce applications.
Unlike languages such as C and C++, garbage collection is a major aspect of the Java language's automated storage management mechanism. It eliminates the need for Java developers to allocate and free memory explicitly, which contributes to the overhead of program speed and the footprint.
Footprint
For an executing Java program, the footprint is affected by many factors:
-
Size of the program
-
Program complexity
-
State objects used by Aurora
-
Capability of the garbage collector and memory manager to cope with the demands of the program
To achieve scalability, it is important to have a minimum incremental per-user session footprint. Oracle's Java Virtual Machine (Aurora) is capable of achieving this requirement by placing read-only data that all users employ, such as Java bytecodes, in shared memory. Different garbage collection algorithms are used, depending on the type of memory. This helps in keeping call and session memory under control.
NOTE
Oracle JServer is architected for scalability because the JServer sessions are garbage-collected independently, resulting in no multiuser garbage collection bottleneck.
Keep in mind that as a developer, you won't have to worry about all the garbage collection that goes on because it is handled automatically by Aurora. However, it is important to understand that Aurora preserves the state of your Java programs between calls by migrating objects reachable by static variables into session space at the end of the call. This indicates that you should use static variables carefully. Improper and unnecessary use of static variables can place a heavy burden on the memory manager and can effectively reduce the scalability. Session space usage can be controlled by avoiding the use of static variables for instance-specific data. The EndOfCallRegistry notification provided by Aurora can be used to clear static variables at the end of call.
Configuring Memory Usage
Two main init.ora parameters affect the memory usage and performance of Java code:
-
Shared_pool_sizeThe shared pool is consumed transiently when you use loadjava. It is also used when call specifications are created and is dynamically loaded Java classes are tracked by the system.
-
java_pool_sizeThe shared in-memory representation of the Java method and class definitions are stored here. These are shared by all the user sessions. In addition, the Java objects that are migrated to session space at the end of the call are also stored here. The java_pool_size must be adjusted based upon the amount of state held in static variables for each session.
Two more init.ora parameters that can affect memory usage per session are as follows:
-
java_soft_sessionspace_limit (default 1MB)Specifies the "soft" limit for the memory usage per session. If this limit is exceeded, a trace file containing a warning is generated.
-
java_max_sessionspace_size (default 4GB)Specifies the maximum limit for the memory usage per session. It this limit is exceeded, Aurora kills the session with an out-of-memory failure message. This is a hidden parameter and should not be modified without consulting Oracle support. An improper setting can make your database unstable.
End-of-Call Optimization
The EndOfCallRegistry class maintains a table of thunk/value pairs known as end-of-call callbacks. At the end of a call, the thunk.act (value) is invoked for every thunk/value pair in the table. However, if the end of the call is also the end of session, the callback is not invoked. After the callback is invoked, it is removed from the table. Several important methods of the EndOfCallRegistry class include these:
-
public static void registerCallback(Callback thunk, Object value)This method installs thunk as an end-of-call callback. At the end of the call, thunk.act (value) will be called for every end-of-call callback. A common variation is to not use the value:
public static void registerCallback(Callback thunk)
-
static void runCallbacks()This method should not be called from your code. It is called by the virtual machine at the end of the call for every thunk/value pair registered using registerCallback.
-
public void act(Object value)This method can be written to do whatever you want for callback purposes, such as notification of the end-of-call.
NOTE
Any object that you want to register using EndOfCallRegistry.registerCallback must implement the oracle.aurora.memoryManager.Callback interface.
Data structures that are candidates for end-of-call optimization include these:
-
Buffers or caches
-
Static fields
-
Dynamically built data structures