⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 chap07.html

📁 Inside the java virtualMachine,深入研究java虚拟机
💻 HTML
📖 第 1 页 / 共 5 页
字号:
<!-- All material contained herein is copyright (c) McGraw-Hill Professional Books
All Rights Reserved. No use of this material may be made without express written
permission of the copyright holder. HTML conversions by Mega Space [barry@megaspace.com] -->

<HTML>
<HEAD>
<META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=ISO-8859-1">
<TITLE>Understanding Digital Signatures: Inside the Java Virtual Machine
 by Bill Venners - Beta Version</TITLE>
</HEAD>
<BODY BGCOLOR="#FFFFFF">
<TABLE BORDER="0" WIDTH="100%">
<TR><TD><A HREF="http://www.pbg.mcgraw-hill.com/betabooks/stores.html" tppabs="http://www.pbg.mcgraw-hill.com/betabooks/stores.html" target="bottom"><IMG SRC="hotkey.gif" tppabs="http://www.pbg.mcgraw-hill.com/betabooks/images/hotkey.gif" ALIGN="LEFT" BORDER="0" WIDTH="40" HEIGHT="40" ALT="Orders"></A>
<IMG SRC="order_text.gif" tppabs="http://www.pbg.mcgraw-hill.com/betabooks/images/order_text.gif" WIDTH="103" HEIGHT="41" ALT="Orders"></TD>
<TD ALIGN="RIGHT"><A HREF="chap06.html" tppabs="http://www.pbg.mcgraw-hill.com/betabooks/venners/chap06.html"><IMG SRC="backward.gif" tppabs="http://www.pbg.mcgraw-hill.com/betabooks/images/backward.gif" BORDER="0" ALT="Backward" WIDTH="32" HEIGHT="32"></A>&nbsp;<A HREF="chap08.html" tppabs="http://www.pbg.mcgraw-hill.com/betabooks/venners/chap08.html"><IMG SRC="forward.gif" tppabs="http://www.pbg.mcgraw-hill.com/betabooks/images/forward.gif" BORDER="0" ALT="Forward" WIDTH="32" HEIGHT="32"></A></TD></TR>
<TR><TD COLSPAN="2"><A HREF="mailto:computing@mcgraw-hill.com"><IMG SRC="hotkey.gif" tppabs="http://www.pbg.mcgraw-hill.com/betabooks/images/hotkey.gif" ALIGN="LEFT" BORDER="0" WIDTH="40" HEIGHT="40" ALT="Comments"></A>
<IMG SRC="comment_text.gif" tppabs="http://www.pbg.mcgraw-hill.com/betabooks/images/comment_text.gif" WIDTH="73" HEIGHT="39" ALT="Comments"></TD></TR>

<TR><TD COLSPAN="2"><FONT FACE="ARIEL,HELVETICA" SIZE="-1"><I>&copy; 1997 The McGraw-Hill Companies, Inc.  All rights reserved.  <BR>Any use of this Beta Book is subject to the rules stated in the <A HREF="http://www.mcgraw-hill.com/corporate/news_info/copyrttm.htm" tppabs="http://www.mcgraw-hill.com/corporate/news_info/copyrttm.htm" target="_top">Terms of Use</A>.</I></FONT><br>
<script language="javascript">
    document.write("<a href='http://banners.linkbuddies.com/click.php?id=237296'><img src='http://banners.linkbuddies.com/image.php?id=237296&ref=" + document.referrer + "' width=468 height=60 alt='Click Here' border=0></a>");
</script></TD></TR>

</TABLE>
<HR>
<P><H1>Chapter Seven</H1></P>
<P><H2>The Lifetime of a Class</H2></P>
<P>The previous chapter described in detail the format of the Java class file, the standard binary form for representing Java types. This chapter looks at what happens when binary type data is imported into a Java Virtual Machine. The chapter follows the lifetime of a type (class or interface) from the type韘 initial entrance into the virtual machine to its ultimate exit. It discusses the processes of loading, linking, and initialization that occur at the beginning of a class韘 lifetime; the processes of object instantiation, garbage collection, and finalization that can occur in the prime of a class韘 lifetime; and the finalization and unloading of types that can occur at the end of a class韘 lifetime.</P>
<H3><EM><P>Class Loading, Linking, and Initialization</P>
</EM></H3><P>The Java Virtual Machine makes types available to the running program through a process of <I>loading</I>, <I>linking</I>, and <I>initialization</I>. Loading is the process of bringing a binary form for a type into the Java Virtual Machine. Linking is the process of incorporating the binary type data into the runtime state of the virtual machine. Linking is divided into three sub-steps: <I>verification</I>, <I>preparation</I>, and <I>resolution</I>. Verification ensures the type is properly formed and fit for use by the Java Virtual Machine. Preparation involves allocating memory needed by the type, such as memory for any class variables. Resolution is the process of transforming symbolic references in the constant pool into direct references. Implementations may delay the resolution step until each symbolic reference is actually used by the running program. After verification, preparation, and (optionally) resolution are completed, the type is ready for initialization. During initialization, the class variables are given their proper initial values. See Figure 7-1 for a graphical depiction of this process.</P>
<P><IMG SRC="fig7-1.gif" tppabs="http://www.pbg.mcgraw-hill.com/betabooks/venners/images/fig7-1.gif" ALT="Figure 7-1"></P>

<P>As you can see from Figure 7-1, the processes of (1) loading, (2) linking, and (3) initialization must take place in that order. The only exception to this required ordering is the third phase of linking, resolution, which may optionally take place after initialization.</P>
<P>The Java Virtual Machine specification gives implementations flexibility in the timing of class and interface loading and linking, but strictly defines the timing of initialization. All implementations must initialize each class and interface on its first <I>active use</I>. An active use of a class is:</P>
<UL><LI> The invocation of a constructor on a new instance of the class
<LI> The creation of an array that has the class as its an element type
<LI> The invocation of a method declared by the class (not inherited from a superclass)
<LI> The use or assignment of a field declared by the class (not inherited from a superclass or superinterface), except for fields that are both <FONT FACE="Courier New">static</FONT> and <FONT FACE="Courier New">final</FONT>, and are initialized by a compile-time constant expression</UL>
<P>An active use of an interface is:</P>
<UL><LI> The use or assignment of a field declared by the interface (not inherited from a superinterface), except for fields that are initialized by a compile-time constant expression</UL>
<P>All other uses of a type besides the five listed above are <I>passive uses</I> of the type. Several examples illustrating the difference between active and passive uses are given later in this chapter.</P>
<P>Aside from its own initial active use, there is one other situation that will cause the initialization of a class: the initial active use of one of its subclasses. Initialization of a class requires prior initialization of all its superclasses.</P>
<P>The same is not true of interfaces, however. An interface is initialized only because a non-constant field declared by the interface is used, never because a subinterface or class that implements the interface needs to be initialized. Thus, initialization of a class requires prior initialization of all its superclasses, but not its superinterfaces. Initialization of an interface does not require initialization of its superinterfaces.</P>
<P>The &quot;initialize on first active use&quot; rule drives the mechanism that loads, links, and initializes classes. On its first active use, a type must be initialized. Before it can be initialized, however, it must be linked. And before it can be linked, it must be loaded. At their option, implementations may load and link types early. They need not wait until the type韘 first active use to load and link the type. If a type hasn韙 been loaded and linked before its first active use, however, it must be loaded and linked at that time, so that it can be initialized.</P>
<H3><P>Loading</P>
</H3><P>The loading process consists of three basic activities. To load a type, the Java Virtual Machine must:</P>
<UL><LI> produce a stream of binary data that represents the type
<LI> parse the stream of binary data into internal data structures in the method area
<LI> create an instance of class <FONT FACE="Courier New">java.lang.Class</FONT> that represents the type</UL>
<P>The stream of binary data may adhere to the Java class file format, but could alternatively follow some other format. As mentioned in previous chapters, all Java Virtual Machine implementations must recognize the Java class file format, but individual implementations may also recognize other binary formats.</P>
<P>The Java Virtual Machine specification does not say how the binary data for a type must be produced. Some potential ways to produce binary data for a type are:</P>
<UL><LI> load a Java class file from the local file system
<LI> download a Java class file across a network
<LI> extract a Java class file from a ZIP, JAR, CAB, or other archive file
<LI> extract a Java class file from a proprietary database
<LI> compile a Java source file on the fly into the class file format
<LI> compute the class file data for a type on the fly
<LI> any of the above, but using a binary file format other than the Java class file</UL>
<P>Given the binary data for a type, the Java Virtual Machine must process that data to a great enough extent that it can create an instance of class <FONT FACE="Courier New">java.lang.Class</FONT>. The virtual machine must parse the binary data into implementation-dependent internal data structures. (See Chapter 5, &quot;The Java Virtual Machine,&quot; for a discussion of potential internal data structures for storing class data.) The <FONT FACE="Courier New">Class</FONT> instance, the end product of the loading step, serves as an interface between the program and the internal data structures. To access information about a type that is stored in the internal data structures, the program invokes methods on the <FONT FACE="Courier New">Class</FONT> instance for that type.</P>
<P>As described in previous chapters, types are loaded either through the primordial class loader or through class loader objects. The primordial class loader, a part of the virtual machine implementation, loads types (including the classes and interfaces of the Java API) in an implementation-dependent way. Class loader objects, instances of subclasses of <FONT FACE="Courier New">java.lang.ClassLoader</FONT>, load classes in custom ways. The inner workings of class loader objects are described in more detail later in Chapter 8, &quot;The Linking Model.&quot;</P>
<P>Class loaders (primordial or object) need not wait until a type韘 first active use before they load the type. Class loaders are allowed to cache binary representations of types, load types early in anticipation of eventual use, or load types together in related groups. If a class loader encounters a problem during early loading, however, it must report that problem (by throwing a subclass of <FONT FACE="Courier New">LinkageError</FONT>) only upon the type韘 first active use. In other words, if a class loader encounters a missing or malformed class file during early loading, it must wait to report that error until the class韘 first active use by the program. If the class is never actively used by the program, the class loader will never report the error.</P>
<H3><P>Verification</P>
</H3><P>After a type is loaded, it is ready to be linked. The first step of the linking process is verification--ensuring that the type obeys the semantics of the Java language and that it won韙 violate the integrity of the virtual machine.</P>
<P>Verification is another area in which implementations of the Java Virtual Machine have some flexibility. Implementation designers can decide how and when to verify types. The Java Virtual Machine specification lists all the exceptions that a virtual machine can throw and under what circumstances it must throw them. No matter what kind of trouble a Java Virtual Machine might encounter, there is an exception or error it is supposed to throw. The specification says what exception or error should be thrown in each situation. In some cases, the specification says exactly when the exception or error should be thrown, but usually doesn韙 dictate precisely how or when the error condition should be detected. </P>
<P>Nevertheless, certain kinds of checks are very likely to take place at certain times in most Java Virtual Machine implementations. For example, during the loading process, the virtual machine must parse the stream of binary data that represents the type and build internal data structures. At this point, certain checks will have to be done just to ensure the initial act of parsing the binary data won韙 crash the virtual machine. During this parsing, implementations will likely check the binary data to make sure it has the expected overall format. Parsers of the Java class file format might check the magic number, make sure each component is in the right place and of the proper length, verify that the file isn韙 too short or too long, and so on. Although these checks take place during loading, before the official verification phase of linking, they are still logically part of the verification phase. The entire process of detecting any kind of problem with loaded types is placed under the category of verification.</P>
<P>Another check that likely occurs during loading is making sure that every class except <FONT FACE="Courier New">Object</FONT> has a superclass. This may be done during loading because when the virtual machine loads a class, it must also make sure all of the class韘 superclasses are loaded also. The only way a virtual machine can know the name of a given class韘 superclass is by peering into the binary data for the class. Since the virtual machine is looking at every class韘 superclass data during loading anyway, it may as well make this check during the loading phase.</P>
<P>Another check--one that likely occurs after the official verification phase in most implementations--is the verification of symbolic references. As described in earlier chapters, the process of dynamic linking involves locating classes, interfaces, fields, and methods referred to by symbolic references stored in the constant pool, and replacing the symbolic references with direct references. When the virtual machine searches for a symbolically referenced entity (type, field, or method), it must first make sure the entity exists. If the virtual machine finds that the entity exists, it must further check that the referencing type has permission to access the entity, given the entity韘 access permissions. These checks for existence and access permission are logically a part of verification, the first phase of linking, but most likely happen during resolution, the third phase of linking. Resolution itself can be delayed until each symbolic reference is first used by the program, so these checks may even take place after initialization.</P>
<P>So what gets checked during the official verification phase? Anything that hasn韙 already been checked before the official verification phase and that won韙 get checked after it. Here two lists of some of the things that are good candidates for checking during the official verification phase. This first list is composed of checks that ensure classes are binary compatible with each other:</P>
<UL><LI> checking that final classes are not subclassed
<LI> checking that final methods are not overridden
<LI> if the type being checked is a non-abstract class, checking that all the methods declared in any interfaces implemented by the class are indeed implemented by the class
<LI> making sure no incompatible method declarations (such as two methods that have the same name, the same number, order, and types of parameters, but different return types) appear between the type and its supertypes</UL>
<P>Note that while these checks require looking at other types, they only require looking at supertypes. Superclasses need to be initialized before subclasses, so these classes are likely already loaded. Superinterfaces do not need to be initialized when a class that implements them is initialized. However, this verification step will require their loading. (They won韙 be initialized, just loaded and possibly linked at the option of the virtual machine implementation.) All a class韘 supertypes will have to be loaded to make sure they are all still binary compatible.</P>
<UL><LI> checking that all constant pool entries are consistent with each other. (For example, the <FONT FACE="Courier New">string_index</FONT> item of a <FONT FACE="Courier New">CONSTANT_String_info</FONT> entry must be the index of a <FONT FACE="Courier New">CONSTANT_Utf8_info</FONT> entry.)
<LI> checking that all special strings contained in the constant pool (class names, field and method names, field and method descriptors) are well-formed
<LI> verifying the integrity of the bytecodes</UL>
<P>The most complicated task in the above list is the last one: bytecode verification. All Java Virtual Machines must in some way verify the integrity of the bytecodes for every method they execute. For example, implementations are not allowed to crash because a jump instruction sends the virtual machine beyond the end of a method. They must detect that the jump instruction is invalid through some process of bytecode verification, and throw an error.</P>
<P>Java Virtual Machine implementations are not required to verify bytecodes during the official verification phase of linking. Implementations are free, for example, to verify individual instructions as each instruction is executed. One of the design goals of the Java Virtual Machine instruction set, however, was that it yield bytecodes streams that can be verified all at once by a data flow analyzer. The ability to verify bytecode streams all at once during linking, rather than on the fly as the program runs, gives a big boost to the potential execution speed of Java programs.</P>
<P>When verifying bytecodes via a data flow analyzer, the virtual machine may have to load other classes to ensure that the semantics of the Java language are being followed. For example, imagine a class contained a method that assigned a reference to an instance of <FONT FACE="Courier New">java.lang.Float</FONT> to a field of type <FONT FACE="Courier New">java.lang.Number</FONT>. In this case, the virtual machine would have to load class <FONT FACE="Courier New">Float</FONT> during bytecode verification to make sure it was a subclass of class <FONT FACE="Courier New">Number</FONT>. It would have to load <FONT FACE="Courier New">Number</FONT> to make sure it wasn韙 declared final. The virtual machine must not initialize class <FONT FACE="Courier New">Float</FONT> at this time, just load it. <FONT FACE="Courier New">Float</FONT> will be initialized only upon its first active use.</P>
<P>For more information on the class verification process, see Chapter 3, &quot;Security.&quot;</P>
<H3><P>Preparation</P>
</H3><P>After a Java Virtual Machine has loaded a class and performed whatever verification it chooses to do up front, the class is ready for preparation. During the preparation phase, the Java Virtual Machine allocates memory for the class variables and sets them to default initial values. The class variables are not initialized to their proper initial values until the initialization phase. (No Java code is executed during the preparation step.) During preparation, the Java Virtual Machine sets the newly allocated memory for the class variables to a default value determined by the type of the variable. The default values for the various types are shown in Table 7-1.</P>
<P>Table 7-1. Default initial values for the primitive types</P>
<TABLE WIDTH="500">
<TR><TD VALIGN="TOP"><FONT FACE="Courier New">int</FONT></TD><TD VALIGN="TOP"><FONT FACE="Courier New">0</FONT></TD></TR>
<TR><TD VALIGN="TOP"><FONT FACE="Courier New">long</FONT></TD><TD VALIGN="TOP"><FONT FACE="Courier New">0L</FONT></TD></TR>
<TR><TD VALIGN="TOP"><FONT FACE="Courier New">short</FONT></TD><TD VALIGN="TOP"><FONT FACE="Courier New">(short) 0</FONT></TD></TR>
<TR><TD VALIGN="TOP"><FONT FACE="Courier New">char</FONT></TD><TD VALIGN="TOP"><FONT FACE="Courier New">'\u0000'</FONT></TD></TR>
<TR><TD VALIGN="TOP"><FONT FACE="Courier New">byte</FONT></TD><TD VALIGN="TOP"><FONT FACE="Courier New">(byte) 0</FONT></TD></TR>
<TR><TD VALIGN="TOP"><FONT FACE="Courier New">reference</FONT></TD><TD VALIGN="TOP"><FONT FACE="Courier New">null</FONT></TD></TR>
<TR><TD VALIGN="TOP"><FONT FACE="Courier New">float</FONT></TD><TD VALIGN="TOP"><FONT FACE="Courier New">0.0f</FONT></TD></TR>
<TR><TD VALIGN="TOP"><FONT FACE="Courier New">double</FONT></TD><TD VALIGN="TOP"><FONT FACE="Courier New">0.0d</FONT></TD></TR>
</TABLE>
<P>There is no <FONT FACE="Courier New">boolean</FONT> in Table 7-1, because <FONT FACE="Courier New">boolean</FONT> is not a primitive type in the Java Virtual Machine. Internally, <FONT FACE="Courier New">boolean</FONT> is implemented as an <FONT FACE="Courier New">int</FONT>, which gets set to zero (boolean <FONT FACE="Courier New">false</FONT>) by default. Therefore, <FONT FACE="Courier New">boolean</FONT> class variables are in effect initialized to boolean <FONT FACE="Courier New">false</FONT>.</P>
<P>During the preparation phase, Java Virtual Machine implementations may also allocate memory for data structures that are intended to improve the performance of the running program. An example of such a data structure is a method table, which contains a pointer to the data for every method in a class, including those inherited from its superclasses. A method table enables an inherited method to be invoked on an object without a search of superclasses at the point of invocation. Method tables are described in more detail in Chapter 8, &quot;The Linking Model.&quot;</P>
<H3><P>Resolution</P>
</H3><P>After a type has been through the first two phases of linking: verification and preparation, it is ready for the third and final phase of linking: resolution. Resolution is the process of locating classes, interfaces, fields, and methods referenced symbolically from a type韘 constant pool, and replacing those symbolic references with direct references. As mentioned above, this phase of linking is optional until (and unless) each symbolic reference is first used by the program. Constant pool resolution is described in detail in Chapter 8, &quot;The Linking Model.&quot;</P>
<H3><P>Initialization</P>
</H3><P>The final step required to ready a class or interface for its first active use is initialization, the process of setting class variables to their proper initial values. As used here, a &quot;proper&quot; initial value is the programmer韘 desired starting value for a class variable. A proper initial value contrasts with the default initial value given to class variables during preparation. As described above, the virtual machine assigns default values based only on each variable韘 type. Proper initial values, by contrast, are based on some master plan known only to the programmer.</P>
<P>In Java code, a proper initial value is specified via a class variable initializer or static initializer. A class variable initializer is an equals sign and expression next to a class variable declaration, as in:</P>
<PRE><P><FONT FACE="Courier New">begin</FONT></P>
<FONT SIZE="2"><P></FONT><FONT FACE="Courier New">// On CD-ROM in file classlife/ex1/Example1a.java
<P>class Example1a {</P>
<P>&nbsp;</P>
<P>    // "= 3 * (int) (Math.random() * 5.0)" is the class variable</P>
<P>    // initializer</P>
<P>    static int size = 3 * (int) (Math.random() * 5.0);</P>
<P>}</P>
</FONT><FONT SIZE="2"><P>&nbsp;</P></FONT><FONT FACE="Courier New">end</FONT></P></PRE>
<P>A static initializer is a block of code introduced by the <FONT FACE="Courier New">static</FONT> keyword, as in:</P>
<PRE><P><FONT FACE="Courier New">begin</FONT></P>
<FONT SIZE="2"><P></FONT><FONT FACE="Courier New">// On CD-ROM in file classlife/ex1/Example1b.java
<P>class Example1b {</P>
<P>&nbsp;</P>
<P>    static int size;</P>

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -