📄 chap09.html
字号:
<OL><LI>Most objects created by most programs have very short lives.</P>
<LI>Most programs create some objects that have very long lifetimes.</OL>
<P>A major source of inefficiency in simple copying collectors is that they spend much of their time copying the same long-lived objects again and again.</P>
<P>Generational collectors address this inefficiency by grouping objects by age and garbage collecting younger objects more often than older objects. In this approach, the heap is divided into two or more sub-heaps, each of which serves one "generation" of objects. The youngest generation is garbage collected most often. As most objects are short-lived, only a small percentage of young objects are likely to survive their first collection. Once an object has survived a few garbage collections as a member of the youngest generation, the object is promoted to the next generation: it is moved to another sub-heap. Each progressively older generation is garbage collected less often than the next younger generation. As objects "mature" (survive multiple garbage collections) in their current generation, they are moved to the next older generation.</P>
<P>The generational collection technique can be applied to mark and sweep algorithms as well as copying algorithms. In either case, dividing the heap into generations of objects can help improve the efficiency of the basic underlying garbage collection algorithm.</P>
<H3><EM><P>Adaptive Collectors</P>
</EM></H3><P>An adaptive garbage collection algorithm takes advantage of the fact that some garbage collection algorithms work better in some situations, while others work better in other situations. An adaptive algorithm monitors the current situation on the heap and adjusts its garbage collection technique accordingly. It may tweak the parameters of a single garbage collection algorithm as the program runs. It may switch from one algorithm to another on the fly. Or it may divide the heap into sub-heaps and use different algorithms on different sub-heaps simultaneously.</P>
<P>With an adaptive approach, designers of Java Virtual Machine implementations need not choose just one garbage collection technique. They can employ many techniques, giving each algorithm work for which it is best suited.</P>
<H3><EM><P>Finalization</P>
</EM></H3><P>In Java, an object may have a finalizer: a method that the garbage collector must run on the object prior to freeing the object. The potential existence of finalizers complicates the job of any garbage collector in a Java Virtual Machine.</P>
<P>To add a finalizer to a class, you simply declare a method in that class as follows:</P>
<PRE><P><FONT FACE="Courier New">begin</FONT></P>
<FONT SIZE="2"><P></FONT><FONT FACE="Courier New">// On CD-ROM in file gc/ex2/Example2.java
<P>class Example2 {</P>
<P> </P>
<P> protected void finalize() throws Throwable {</P>
<P> //...</P>
<P> super.finalize();</P>
<P> }</P>
<P> //...</P>
<P>}</P>
</FONT><FONT SIZE="2"><P> </P></FONT><FONT FACE="Courier New">end</FONT></P></PRE>
<P>A garbage collector must examine all objects it has discovered to be unreferenced to see if any include a <FONT FACE="Courier New">finalize()</FONT> method.</P>
<P>Because of finalizers, a garbage collector in the Java Virtual Machine must perform some extra steps each time it garbage collects. First, the garbage collector must in some way detect unreferenced objects (call this Pass I). Then, it must examine the unreferenced objects it has detected to see if any declare a finalizer. If it has enough time, it may at this point in the garbage collection process finalize all unreference objects that declare finalizers.</P>
<P>After executing all finalizers, the garbage collector must once again detect unreferenced objects starting with the root nodes (call this Pass II). This step is needed because finalizers can "resurrect" unreferenced objects and make them referenced again. Finally, the garbage collector can free all objects that were found to be unreferenced in both Passes I and II.</P>
<P>To reduce the time it takes to free up some memory, a garbage collector can optionally insert a step between the detection of unreferenced objects that have finalizers and the running of those finalizers. Once the garbage collector has performed Pass I and found the unreferenced objects that need to be finalized, it can run a miniature trace starting not with the root nodes but with the objects waiting to be finalized. Any objects that are (1) not reachable from the root nodes (those detected during Pass I) and (2) not reachable from the objects waiting to be finalized cannot be resurrected by any finalizer. These objects can be freed immediately.</P>
<P>If an object with a finalizer becomes unreferenced, and its finalizer is run, the garbage collector must in some way ensure that it never runs the finalizer on that object again. If that object is resurrected by its own finalizer or some other object韘 finalizer and later becomes unreferenced again, the garbage collector must treat it as an object that has no finalizer.</P>
<P>As you program in Java, you must keep in mind that it is the garbage collector that runs finalizers on objects. Because it is not generally possible to predict exactly when unreferenced objects will be garbage collected, it is not possible to predict when object finalizers will be run. As mentioned in Chapter 2, "Platform Independence," you should avoid writing programs for which correctness depends upon the timely finalization of objects. For example, if a finalizer of an unreferenced object releases a resource that is needed again later by the program, the resource will not be made available until after the garbage collector has run the object finalizer. If the program needs the resource before the garbage collector has gotten around to finalizing the unreferenced object, the program is out of luck.</P>
<H3><EM><P>Heap of Fish: A Simulation </P>
</EM></H3><P>The <I>Heap of Fish</I> applet, shown in Figures 9-2 through 9-5, demonstrates a compacting, mark and sweep, garbage-collected heap. To facilitate compaction, this heap uses indirect handles to objects instead of direct references. It is called <I>Heap of Fish</I> because the only type of objects stored on the heap for this demonstration are fish objects, defined as follows:</P>
<P><FONT FACE="Courier New">insert</FONT></P>
<FONT SIZE="2"><P></FONT><FONT FACE="Courier New">// On CD-ROM in file gc/ex1/YellowFish.java
<P>class YellowFish {</P>
<P> </P>
<P> YellowFish myFriend;</P>
<P>}</P>
</FONT><FONT SIZE="2"><P> </P></P>
<P></FONT><FONT FACE="Courier New">// On CD-ROM in file gc/ex1/BlueFish.java
<P>class BlueFish {</P>
<P> </P>
<P> BlueFish myFriend;</P>
<P> YellowFish myLunch;</P>
<P>}</P>
</FONT><FONT SIZE="2"><P> </P></P>
<P></FONT><FONT FACE="Courier New">// On CD-ROM in file gc/ex1/RedFish.java
<P>class RedFish {</P>
<P> </P>
<P> RedFish myFriend;</P>
<P> BlueFish myLunch;</P>
<P> YellowFish mySnack;</P>
<P>}</P>
</FONT><FONT SIZE="2"><P> </P></FONT><FONT FACE="Courier New">end</FONT></P></PRE>
<P>As you can see, there are three classes of fish: red, yellow, and blue. The red fish is the largest as it has three instance variables. The yellow fish, with only one instance variable, is the smallest fish. The blue fish has two instance variables and is therefore medium-sized. </P>
<P>The instance variables of fish objects are references to other fish objects. <FONT FACE="Courier New">BlueFish.myLunch</FONT>, for example, is a reference to a <FONT FACE="Courier New">YellowFish</FONT> object. In this implementation of a garbage-collected heap, a reference to an object occupies four bytes. Therefore, the size of the instance data of a <FONT FACE="Courier New">RedFish</FONT> object is twelve bytes, a <FONT FACE="Courier New">BlueFish</FONT> object is eight bytes, and a <FONT FACE="Courier New">YellowFish</FONT> object is four bytes.</P>
<P><I>Heap of Fish</I> has five modes, which can be selected via radio buttons at the bottom left of the applet. When the applet starts it is in swim mode. Swim mode is just a gratuitous animation, vaguely reminiscent of the familiar image of a big fish about to eat a medium-sized fish, which is about to eat a small fish. The other four modes--allocate fish, assign references, garbage collect, and compact heap--allow you to interact with the heap. In the allocate fish mode, you can instantiate new fish objects. In the assign references mode, you can build a network of local variables and fish that refer to other fish. In garbage collect mode, a mark and sweep operation will free any unreferenced fish. The compact heap mode allows you to slide heap objects so that they are side by side at one end of the heap, leaving all free memory as one large contiguous block at the other end of the heap.</P>
<H3><P>Allocate Fish </P>
</H3><P> The allocate fish mode, shown in Figure 9-2, allows you to allocate new fish objects on the heap. In this mode you can see the two parts that make up the heap: the object pool and handle pool. The object pool is a contiguous block of memory from which space is taken for new objects. It is structured as a series of memory blocks. Each memory block has a four-byte header that indicates the length of the memory block and whether or not it is free. The headers are shown in the applet as black horizontal lines in the object pool.</P>
<P><IMG SRC="fig9-2.gif" tppabs="http://www.pbg.mcgraw-hill.com/betabooks/venners/images/fig9-2.gif" ALT="Figure 9-2"><BR>
Figure 9-2. The allocate fish mode of the <I>Heap of Fish</I> applet.</P>
<P>The object pool in <I>Heap of Fish</I> is implemented as an array of <FONT FACE="Courier New">int</FONT>s. The first header is always at <FONT FACE="Courier New">objectPool[0]</FONT>. The object pool's series of memory blocks can be traversed by hopping from header to header. Each header gives the length of its memory block, which also reveals where the next header is going to be. The header of the next memory block will be the first <FONT FACE="Courier New">int</FONT> immediately following the current memory block.</P>
<P>When a new object is allocated, the object pool is traversed until a memory block is encountered with enough space to accommodate the new object. Allocated objects in the object pool are shown as colored bars. <FONT FACE="Courier New">YellowFish</FONT> objects are shown in yellow, <FONT FACE="Courier New">BlueFish</FONT> in blue, and in red. Free memory blocks, those that currently contain no fish, are shown in white.</P>
<P>The handle pool in <I>Heap of Fish</I> is implemented as an array of objects of a class named <FONT FACE="Courier New">ObjectHandle</FONT>. An <FONT FACE="Courier New">ObjectHandle</FONT> contains information about an object, including the vital index into the object pool array. The object pool index functions as a reference to the object韘 instance data in the object pool. The <FONT FACE="Courier New">ObjectHandle</FONT> also reveals information about the class of the fish object. As mentioned in Chapter 5, "The Java Virtual Machine," every object on the heap must in some way be associated with its class information stored in the method area. In <I>Heap of Fish</I>, the <FONT FACE="Courier New">ObjectHandle</FONT> associates each allocated object with information such as its class--whether it is a <FONT FACE="Courier New">RedFish</FONT>, <FONT FACE="Courier New">BlueFish</FONT>, or <FONT FACE="Courier New">YellowFish</FONT>--and some data used in displaying the fish in the applet user interface.</P>
<P>The handle pool exists to make it easier to defragment the object pool through compaction. References to objects, which can be stored in local variables of a stack or the instance variables of other objects, are not direct indexes into the object pool array. They are instead indexes into the handle pool array. When objects in the object pool are moved for compaction, only the corresponding <FONT FACE="Courier New">ObjectHandle</FONT> must be updated with the object's new object pool array index.</P>
<P>Each handle in the handle pool that refers to a fish object is shown as a horizontal bar painted the same color as the fish to which it refers. A line connects each handle to its fish instance variables in the object pool. Those handles that are not currently in use are drawn in white.</P>
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -