|
|
Content: |
|
Classes in binary format |
Bytecode and stack |
Load class |
Conclusion |
References |
About the author |
Comments on this article |
|
|
Related content: |
|
Tutorial: learn more about Java classloader |
Measure Java local Compilation |
How to block your (or open others') Java code |
The jikes research Virtual Machine (rvm) |
Developerworks toolbox subscription |
|
|
The Java area also contains: |
|
Teaching |
Tools and products |
Code and components |
All articles |
Practical Skills |
|
|
Research Class and what happens when JVM loads a class Level: Intermediate Dennis M. sosnoski (dms@sosnoski.com) President, sosnoski software solutions, Inc. June 2003
This new series on Java programming DynamicsArticleThe Java application is studied.ProgramEvents happening behind the scenes. Enterprise Java expert Dennis sosnoski provides an overview of the Java binary class format and the situation of classes in the JVM. Next, he will discuss the class loading problem, the scope covers the number of classes required to run simple Java applications to the Class Loader conflicts that may cause problems in J2EE and similar complex architectures.
This is the first article in this new series.Dynamic nature of Java programming. These topics range from the basic structure of the Java binary file format and runtime metadata access using reflection until new classes are modified and constructed at runtime. The public clue throughout the article is the idea that programming on the Java platform is much better than using a machine with a direct compilation cost.CodeThe language is more dynamic. If you understand these dynamic aspects, you can use Java programming to complete those in any other mainstreamProgramming Language. In this article, I will discuss some basic concepts that are the basis of dynamic features of these Java platforms. The core of these concepts is to express the binary format of Java classes, including what happens when these classes are loaded into the JVM. This article is not only the basis of the remaining articles in this series, but also demonstrates some very practical problems encountered by developers when using the Java platform. Classes in binary format Developers using the Java language compile theirSource codeUsually do not care about the details of these source code. However, in this series of articles, I will discuss many background details from the source code to the execution program, so I will first discuss the binary classes generated by the compiler. The binary format is actually defined by the JVM specification. These classes are usually generated by the compiler from the Java source code, and they are usually stored in. Class . However, these features are irrelevant. Other programming languages that can use the Java binary class format have been developed. For some purposes, a new class representation has been built and immediately loaded into the running JVM. For JVM, the important part is not the source code and how to store the source code, but the format itself. What does the class format actually look like? Listing 1 provides the source code of a (very) short class and a hexadecimal display of the class file output by the compiler: Listing 1. source code and (partial) binary files of Hello. Java
public class Hello {public static void main (string [] ARGs) {system. Out. println ("Hello, world! ") ;}} 0000: cafe babe 0000 002e 001a 0a00 0600 0c09 ................ 0010: 000d 000e 0800 0f0a 0010 0011 0700 1207 ................ 0020: 0013 0100 063c 696e 6974 3e01 0003 2829 .....
... () 0030: 5601 0004 436f 6465 0100 046d 6169 6e01 v... code... main.0040: 0016 285b 4c6a 6176 612f 6c61 6e67 2f53 .. ([ljava/lang/s0050: 7472 696e 673b 2956 0c00 0700 0807 0014 tring;) V ........ 0060: 0c00 1500 1601 00 0d 4865 6c6c 6f2c 2057 ...... hello, w0070: 6f72 6c64 2107 0017 0c00 1800 1901 0005 orld !........... 0080: 4865 6c6c 6f01 0010 6a61 7661 2f6c 616e hello... java/lan0090: 672f 4f62 6a65 6374 0100 106a 6176 612f g/object... java/00a0: 6c61 6e67 2f53 7973 7465 6d01 0003 6f75 lang/system... ou...
|
Overview of binary files The binary class shown in Listing 1 indicates the first "cafe babe" feature character, it identifies the Java binary format (and, by the way, serves as a permanent-but largely unrecognized-gift for hard-workingBaristaThey build the Java platform in the spirit of developers ). This feature is exactly a way to verify a data block.IndeedA simple method to declare an instance in Java class format. Any Java binary class (or even a class that does not appear in the file system) must start with these four bytes. The rest of the data is not very attractive. This feature is followed by a version number in the class format (in this example, the minor version 0 generated by 1.4.1 javac and the primary version 46-0x2e in hexadecimal notation ), the total number of items in the constant pool. The total number of items (26 in this example, or 0x001a) is followed by the actual constant pool data. All constants used by the class definition are placed here. It includes class names, method names, feature characters, and strings (you can identify them in the text interpretation on the right of the hexadecimal dump), as well as various binary values. The length of each item in the constant pool is variable. The first byte of each item identifies the type of the item and the method of decoding it. I will not go into the details of all these content here. If you are interested, there are many available references starting with the actual JVM specification. The key lies in that the constant pool contains all references to other classes and methods used by the class, as well as the actual definitions of the class and its methods. The constant pool usually accounts for half or more of the binary class size, but the average size may be less. There are several items after the constant pool, which reference the constant pool items of the class itself, its superclasses, and interfaces. These items are followed by information about fields and methods, which are expressed in a complex structure. Method executable code to be included in the method definitionCode attributes. The code is expressed in the form of JVM commands.BytecodeThis is one of the topics to be discussed in the next section. In Java format,AttributeIt is used for several defined purposes, including the mentioned bytecode, field constant value, exception handling, and debugging information. However, attributes are not only used for these purposes. From the very beginning, the JVM specification requires JVM to ignore unknown attributes. The flexibility brought by this requirement makes it possible to extend the usage of attributes for other purposes in the future, such as providing metadata required for frameworks that use user classes, this method is widely used in C # language derived from Java. Unfortunately, no hooks have been provided for the use of this flexibility at the user level. Bytecode and stack The bytecode that constitutes the executable part of a class file is actually the machine code for a specific type of computer-JVM. It is calledVirtualMachine, because it is designed to be implemented by software rather than hardware. Every JVM used to run Java platform applications is built around the implementation of this machine. This virtual machine is actually quite simple. It uses the stack architecture, which means to load the instruction operands into the internal stack first. The instruction set includes all General Arithmetic and logical operations, as well as conditional and unconditional transfer, loading/storage, call/return, stack operations, and several special types of commands. Some commands contain immediate operation values, which are directly encoded into the commands. Other commands directly reference values in the constant pool. Although the virtual machine is simple, this is not the case. Early (First Generation) JVM was basically the interpreter of the Virtual Machine bytecode. These virtual machines actuallyIndeedRelatively simple, but there are serious performance problems-the time to interpret the code is always longer than the time to execute the local code. To reduce these performance problems, the second-generation JVM has been addedInstant(Just-in-time, JIT) conversion. Prior to the first execution of Java bytecode, JIT Technology compiled the cost machine code to provide better performance for repeated execution. The performance of contemporary JVM is even better, because adaptive technologies are used to monitor program execution and selectively optimize frequently-used code. Load class Languages such as C and C ++ that compile the machine code usually need to link this step after compiling the source code. This link combines the code from the independently compiled source files with the shared library code to form an executable program. The Java language is different. In Java, the classes generated by the compiler are normally the same before they are loaded into the JVM. This is not changed even if you build a jar file from the class file-jar is only the container of the class file. A linked class is not an independent step. It is part of the job executed when the JVM loads these classes into the memory. This step adds some overhead when you initially mount the class, but also provides high flexibility for Java applications. For example, you can specify the actual implementation only when writing an application to use an interface. This is used to assemble the applicationPost-joint editingThe method is widely used on the Java platform. servlet is a common example. The JVM specification details the rules for loading classes. The basic principle is to load classes only when needed (or at least it looks like this-JVM has some flexibility in actual loading, but it must maintain a fixed class initialization order ). Each loaded class may have other dependent classes, so the loading process is recursive. The class in Listing 2 shows how this recursive load works.Demo Class contains a simpleMain Method, it createsGreeter And callGreet Method.Greeter The constructor has createdMessage And thenGreet Method call. Listing 2. source code of the class loading demonstration
Public class demo {public static void main (string [] ARGs) {system. out. println ("** beginning execution **"); greeter = new greeter (); system. out. println ("** created greeter **"); greeter. greet () ;}} public class greeter {private static message s_message = new message ("Hello, world! "); Public void greet () {s_message.print (system. out) ;}} public class message {private string m_text; public message (string text) {m_text = text;} public void print (Java. io. printstream PS) {ps. println (m_text );}}
|
InJava Set parameters on the command line-Verbose: Class The tracing record of the class loading process is printed. Listing 3 shows part of the output of running the Listing 2 program using this parameter: Listing 3.-verbose: Partial output of class
[Opened/usr/Java/j2sdk1.4.1/JRE/lib/RT. jar] [opened/usr/Java/j2sdk1.4.1/JRE/lib/sunrsasign. jar] [opened/usr/Java/j2sdk1.4.1/JRE/lib/JSSE. jar] [opened/usr/Java/j2sdk1.4.1/JRE/lib/JCE. jar] [opened/usr/Java/j2sdk1.4.1/JRE/lib/charsets. jar] [loaded Java. lang. object from/usr/Java/j2sdk1.4.1/JRE/lib/RT. jar] [loaded Java. io. serializable from/usr/Java/j2sdk1.4.1/JRE/lib/RT. jar] [loaded Java. lang. comparable From/usr/Java/j2sdk1.4.1/JRE/lib/RT. jar] [loaded Java. lang. charsequence from/usr/Java/j2sdk1.4.1/JRE/lib/RT. jar] [loaded Java. lang. string from/usr/Java/j2sdk1.4.1/JRE/lib/RT. jar]... [loaded Java. security. principal From/usr/Java/j2sdk1.4.1/JRE/lib/RT. jar] [loaded Java. security. cert. certificate from/usr/Java/j2sdk1.4.1/JRE/lib/RT. jar] [loaded demo] ** beginning execution ** [loaded greeter] [loaded mess Age] ** created greeter ** Hello, world! [Loaded Java. util. hashmap $ keyset from/usr/Java/j2sdk1.4.1/JRE/lib/RT. jar] [loaded Java. util. hashmap $ keyiterator from/usr/Java/j2sdk1.4.1/JRE/lib/RT. jar]
|
This only lists the most important parts of the output-the complete trace record consists of 294 rows. I deleted most of the records to form this list. The first group of classes is loaded (279 in this example ).Demo Class. These classes are the core classes used by every Java program (no matter how small. Even if you deleteDemo main All the code of the method does not affect the initial loading order. However, the number and name of classes involved in different versions of the class library are different. In the above list, loadDemo The section after the class is more interesting. The sequence shown here only shows thatGreeter Class. However,Greeter Class usedMessage So you can createGreeter You must loadMessage Class. When a class is loaded and initialized, the JVM performs many operations, including decoding the binary format, checking compatibility with other classes, verifying the sequence of Bytecode operations, and final construction.Java. Lang. Class Instance to represent the new class. ThisClass Object is the basis for JVM to create all instances of the new class. It is also the identifier of the mounted class itself-for the same binary class loaded into JVM, there can be multiple copies, each of which has its ownClass Instance. Even if these copies share the same class name, they are all independent classes for JVM. Unconventional (class) path The classes loaded to JVM are composedClass Loader. ABootstrap programClass Loader, which is responsible for loading Basic Java class libraries. This special class loader has some special features. First, it is loaded only to the class found on the boot class path. Because these are trusted system classes, the bootstrap loader skips a lot of verification on the regular (untrusted) classes. The Bootstrap program is not the only class loader. For beginners, JVM definesExtensionClass Loader, and definesSystemClass Loader. Applications can also define their own class loaders for special purposes (such as re-loading runtime classes. The class loader is derived fromJava. Lang. classloader Class (which may be indirectly derived). This class constructs an internal class representation from the byte array (Java. Lang. Class Instances. In a sense, each constructed class is "owned" by the class loader that loads it ". The Class Loader usually retains the ing of the loaded classes, so that the class can be found by name when a class is requested again. Each class loader also retains references to the parent class loader, which defines the Class Loader tree and the root of the tree is the loader. When an instance of a specific class is required (identified by the name), no matter which class loader initially processes the request, before attempting to directly mount the class, generally, the parent class loader is checked first. If there is a multi-layer class loader, this step will be performed recursively, so this means that not onlyVisibleAnd is visible to all future class loaders. This also means that if a chain contains multiple class loaders that can load a class, the class loader at the top of the tree will actually load the class loader. In many environments, Java programs use multiple application class loaders. The J2EE framework is an example. Each J2EE application loaded by the framework must have an independent class loader to prevent the classes in one application from interfering with other applications. The Framework Code itself will also use one or more other class loaders to prevent interference to or from applications. The entire class loader set forms a hierarchy of tree structures, and different classes can be loaded at each level. Loader tree As an actual example of the Class Loader hierarchy, Figure 1 shows the Class Loader hierarchy defined by the Tomcat Servlet Engine. Here, the common class loader is loaded from a jar file in a specific directory installed by Tomcat to share code between the server and all web applications. The Catalina loader is used to load Tomcat's own classes, while the shared loader is used to load classes shared between Web applications. Finally, each web application has its own loader for its private class. Figure 1. Tomcat Loader
In this environment, it is confusing to track the appropriate loader for requesting new classes. Therefore, in the Java 2 platformSetcontextclassloader Method andGetcontextclassloader Method addedJava. Lang. Thread Class. These methods allow the framework to set the Class Loader so that the class loader can be used to run the code in each application. The flexibility of loading an independent class set is an important feature of the Java platform. Although this feature is useful, it may cause confusion in some cases. A confusing aspect is dealing with old issues such as JVM class paths. For example, in the Tomcat Class Loader hierarchy shown in figure 1, classes loaded by the common Class Loader cannot directly access the classes loaded by Web applications (according to the name. The only way to associate these classes together is to use interfaces visible to both classes. In this example, Java Servlet implementsJavax. servlet. servlet . Whatever the cause may occur when code is moved between class loaders. For example, when j2se 1.4 moves the jaxp api for XML processing to the standard distribution edition, problems may occur in many environments, because the applications in these environments previously relied on loading their own xml api implementation. With j2se 1.3, you only need to include the appropriate JAR file in the user class path to solve this problem. In j2se 1.4, the standard version of these Apis is now in the extended class path, so they will usually overwrite any implementation in the user class path. Using multiple classloaders may also cause confusion of other types. Figure 2 showsClass Identity Crisis)In this example, it is a crisis when two independent class loaders load an interface and its related implementations. Even if the names and binary implementations of interfaces and classes are the same, instances of classes from one loader cannot be considered to implement interfaces from another loader. In Figure 2I You can remove this confusion by moving to the space of the system class loader. ClassA There are still two independent instances, but they all implement the same interfaceI . Figure 2. Class Identity Crisis
Conclusion Together with the JVM specification, Java class definitions define an extremely powerful framework for runtime assembly code. By using the class loader, Java applications can use classes of multiple versions. Otherwise, these classes may cause conflicts. The flexibility of the Class Loader even allows you to dynamically reload the modified Code while the application continues to execute. Here, the flexibility of the Java platform is at the cost of starting an application to some extent. Before JVM can start executing or even the simplest application code, it must load hundreds of independent classes. Compared with frequently-used small programs, this startup cost usually makes Java platform more suitable for long-running server-type applications. Server applications also benefit most from the flexibility of code assembly during runtime, so it is not surprising that Java platforms are increasingly favored for such development. in part 1 of this series, I will introduce another aspect of using the dynamic Foundation of the Java platform: reflection API ). Reflection allows the Execution code to access internal class information. This may be an excellent tool for building flexible code. You can link the Code together at runtime without using any source code links between classes. But like most tools, you must know when and how to use them for maximum benefit. Read dynamic Java programming section 2nd to learn the tricks and pros and cons of effective reflection. References
-
- Go directlyThe Java virtual machine specificationTo understand the binary class format, class loading, and actual Java bytecode.
-
- Read the Tutorial "learning about Java classloader" written by Greg Travis "(DeveloperworksApril 2001) learn all the details about building your own special class loaders.
-
- Martyn honeyford's popular article "Measuring Java native compilation (DeveloperworksJanuary 2002) provides more details about the Java language native code compilation problems and their advantages and disadvantages.
- The binary format contains a large amount of important information, which is usually enough for you to reconstruct the source code (except for comments ). In greg Travis's article "how to lock down your Java code (or open up someone else's (DeveloperworksMay 2001), he showed you how to use this information.
-
- Get details about jikes research Virtual Machine (rvm), which is implemented in Java and self-managed (that is, its Java code runs on its own, another virtual machine is not required ).
-
- Use a metadata facility for the Java programming language of java standard request 175 (Java specification request 175, JSR 175) to keep up with the development that enables attributes to be used by Java developers.
-
- Understand the details of the Apache Tomcat Java Web server project of the Apache Software Foundation, including the usage details of the Tomcat class loader.
-
- InDeveloperworksYou can find hundreds of Java technical references in the Java technology zone.
About the author Dennis sosnoski is the founder and Chief Consultant of sosnoski software solutions, Inc., a Java consulting firm in Seattle. He is an expert in J2EE, XML, and Web service support. He has more than 30 years of professional software development experience and has concentrated on the Java technology of the server in recent years. Dennis often gives speeches on XML and Java technologies at national conferences. He is also the chairman of the Seattle Java-XML Sig. You can contact Dennis through a dms@sosnoski.com. |
|