Oracle8i Java Developer's Guide
Release 3 (8.1.7)

Part Number A83728-01

Library

Product

Contents

Index

Go to previous page Go to beginning of chapter Go to next page

Why Use Java in Oracle8i?

The only reason that you are allowed to write and load Java applications within the database is because it is a safe language. Java has been developed to prevent anyone tampering with the operating system that the Java code resides in. Some languages, such as C, can introduce problems within the database. Java, because of its design, is a safe language to allow within the database.

Although the Java language presents many advantages to developers, providing an implementation of a JVM that supports Java server applications in a scalable manner is a challenge. This section discusses some of these challenges.

Multithreading

Multithreading support is often cited as one of the key scalability features of the Java language. Certainly, the Java language and class libraries make it simpler to write multithreaded applications in Java than many other languages, but it is still a daunting task in any language to write reliable, scalable multithreaded code.

As a database server, Oracle8i efficiently schedules work for thousands of users. The Oracle8i Aurora JVM uses the facilities of the RDBMS server to concurrently schedule Java execution for thousands of users. Although Oracle8i supports Java language level threads required by the Java language specification (JLS) and Java Compatibility Kit (JCK), using threads within the scope of the database will not increase your scalability. Using the embedded scalability of the database eliminates the need for writing multithreaded Java servers. You should use the database's facilities for scheduling users by writing single-threaded Java applications. The database will take care of the scheduling between each application; thus, you achieve scalability without having to manage threads. You can still write multithreaded Java applications, but multiple Java threads will not increase your server's performance.

One difficulty multithreading imposes on Java is the interaction of threads and automated storage management, or garbage collection. The garbage collector executing in a generic JVM has no knowledge of which Java language threads are executing or how the underlying operating system schedules them.

Automated Storage Management

Garbage collection is a major feature of Java's automated storage management, eliminating the need for Java developers to allocate and free memory explicitly. Consequently, this eliminates a large source of memory leaks that commonly plague C and C++ programs. There is a price for such a benefit: garbage collection contributes to the overhead of program execution speed and footprint. Although many papers have been written qualifying and quantifying the trade-off, the overall cost is reasonable, considering the alternatives.

Garbage collection imposes a challenge to the JVM developer seeking to supply a highly scalable and fast Java platform. Aurora's JVM meets these challenges in the following ways:

Footprint

The footprint of an executing Java program is affected by many factors:

From a scalability perspective, the key to supporting many concurrent clients is a minimum per-user session footprint. Aurora keeps the per-user session footprint to a minimum by placing all read-only data for users, such as Java bytecodes, in shared memory. Appropriate garbage collection algorithms are applied against call and session memories to maintain a small footprint for the user's session. Aurora uses three types of garbage collection algorithms to maintain the user's session memory:

Performance

JServer performance is enhanced by implementing a native compiler.

How Native Compilers Improve Performance

Java executes platform-independent bytecodes on top of a JVM, which in turn deals with the specific hardware platform. Anytime you add levels within software, your performance is degraded. Because Java requires going through an intermediary to interpret platform-independent bytecodes, a degree of inefficiency exists for Java applications that does not exists within a platform-dependent language, such as C. To address this issue, several JVM suppliers create native compilers. Native compilers translate Java bytecodes into platform-dependent native code. This eliminates the interpreter step and improves performance. The following describes two methods for native compilation:

Compiler   Description  

Just In Time (JIT) Compilation  

JIT compilers quickly compile Java bytecodes to native (platform-specific) machine code during runtime. This does not produce an executable to be executed on the platform; instead, it provides platform-dependent code from Java bytecodes that is executed directly after it is translated. This should be used for Java code that is run frequently, which will be executed at speeds closer to languages such as C.  

Static Compilation  

Static compilation translates Java bytecodes to platform-independent C code before runtime. Then, a standard C compiler compiles the C code into an executable for the target platform. This approach is more suitable for Java applications that are modified infrequently. This approach takes advantage of the mature and efficient platform-specific compilation technology found in modern C compilers.  

Oracle8i uses static compilation to deliver its core Java class libraries, the Aurora/ORB, and JDBC code in natively compiled form. It is applicable across all the platforms Oracle supports, whereas a JIT approach requires low-level, processor-dependent code to be written and maintained for each platform. You can use this native compilation technology with your own Java code. Refer to "Natively Compiled Code" for more information.

Dynamic Class Loading

Another strong feature of Java is dynamic class loading. The class loader loads classes from the disk (and places them in the JVM-specific memory structures necessary for interpretation) only as they are used during program execution. The class loader locates the classes in the CLASSPATH and loads them during program execution. This approach, which works well for applets, poses the following problems in a server environment:

Problem   Description   Solution  

Predictability  

The class loading operation places a severe penalty on first-time execution. A simple program can cause Aurora to load many core classes to support its needs. A programmer cannot easily predict or determine the number of classes Aurora loads.  

Aurora loads classes dynamically, just as with any other Java virtual machine. The same one-time class loading speed hit is encountered. However, because Aurora loads the classes into shared memory, no other users of those classes will cause the classes to load again--they will simply use the same pre-loaded classes.  

Reliability  

A benefit of dynamic class loading is that it supports program updating. For example, you would update classes on a server, and clients who download the program and load it dynamically see the update whenever they next use the program. Server programs tend to emphasize reliability. As a developer, you must know that every client executes a specific program configuration. You do not want clients to inadvertently load some classes that you did not intend them to load.  

Oracle8i separates the upload and resolve operation from the class loading operation at runtime. You upload Java code you developed to the server using the loadjava utility. Instead of using CLASSPATH, you specify a resolver at installation time. The resolver is analogous to CLASSPATH, but allows you to specify the schemas in which the classes reside. This separation of resolution from class loading means you always know what program users execute. Refer to the Oracle8i Java Tools Reference, for details on loadjava and resolvers.  



Go to previous page
Go to beginning of chapter
Go to next page
Oracle
Copyright © 1996-2000, Oracle Corporation.

All Rights Reserved.

Library

Product

Contents

Index