1. Field of the Invention
This invention relates generally to the Java™ platform, and more particularly to methods and systems for minimizing main memory consumption associated with defining class loading policies in Java.
2. Description of the Related Art
Although the ability to produce and execute portable, architectural-neutral code (i.e., bytecode) is desirable, the method used to execute this code can be inefficient. Unlike native code, which is code compiled into a series of instructions that correlate directly to a microprocessor's instruction set, bytecode (e.g., Java bytecode) must be interpreted by a virtual machine (e.g., Java virtual machine (JVM)), whereby the virtual machine must locate for each bytecode instruction an equivalent sequence of microprocessor instruction that the virtual machine then executes. Obviously, interpretation takes some amount of time and it can be inherently slower than directly executing equivalent native code.
To make the execution of bytecode more efficient, modern virtual machines use dynamic compilation (i.e., compilation performed at runtime) to reduce the overhead of interpretation. In a typical virtual machine, the invocation of interpreted methods is monitored and the most frequently used methods are compiled by a dynamic compiler at runtime. Once a method has been dynamically compiled, its invocation results in executing the native code produced by the compilation instead of interpreting the method's bytecode. The overhead of dynamic compilation is offset by the increased performance obtained from executing native code.
One of the most distinctive features of the Java programming language is the ability to define class loading policies. Class loaders allow a program to define classes in separate namespaces and to control the location where to fetch the architecture-neutral representation of the classes. The ability to create separate namespaces allows a program to define multiple classes from the same class definition, or to define multiple versions of the same class.
These features enable the implementation of some form of isolation, where the software components can be defined multiple times by a program without interfering with each other. They also give programs an opportunity to transparently enhance code submitted by a third-party by allowing its interception and modification (via bytecode transformation) before the code is linked with the rest of a running program.
However, using class loaders comes at a cost. JVM implementations typically replicate the entire runtime representation of a class in memory for each class loader that defines the class. Defining a class multiple times also replicates the effort to create an optimized runtime representation, by repeating the same parsing of class file, construction of a main-memory runtime representation, bytecode verification, quickening of bytecodes, resolution of constants, and identification and dynamic compilation of frequently used methods.
One approach to eliminate the costs of dynamic compilation uses the delegation of relationships between class loaders, where one class loader can delegate the definition of a class to another class, to help limit these problems. However, delegation can rapidly become error prone as the complexity of the delegation relationships increases. Besides, not all uses of class loader can be accommodate with delegation. For instance, delegation is inadequate when multiple instances of the same software component must be loaded and isolated from each other.
In view of the foregoing, there is a need for a method that can reduce the memory consumption of defining multiple times the same class with different user-defined class loaders, and can amortize the costs of dynamic compilation across these defining loaders.