📄 gcheap.java
字号:
/*
* Copyright (c) 1996, 1997 Bill Venners. All Rights Reserved.
*
* This Java source file is part of the Interactive Illustrations Web
* Site, which is delivered in the applets directory of the CD-ROM
* that accompanies the book "Inside the Java Virtual Machine" by Bill
* Venners, published by McGraw-Hill, 1997,ISBN: 0-07-913248-0. This
* source file is provided for evaluation purposes only, but you can
* redistribute it under certain conditions, described in the full
* copyright notice below.
*
* Full Copyright Notice:
*
* All the web pages and Java applets delivered in the applets
* directory of the CD-ROM, consisting of ".html," ".gif," ".class,"
* and ".java" files, are copyrighted (c) 1996, 1997 by Bill
* Venners, and all rights are reserved. This material may be copied
* and placed on any commercial or non-commercial web server on any
* network (including the internet) provided that the following
* guidelines are followed:
*
* a. All the web pages and Java Applets (".html," ".gif," ".class,"
* and ".java" files), including the source code, that are delivered
* in the applets directory of the CD-ROM that
* accompanies the book must be published together on the same web
* site.
*
* b. All the web pages and Java Applets (".html," ".gif," ".class,"
* and ".java" files) must be published "as is" and may not be altered
* in any way.
*
* c. All use and access to this web site must be free, and no fees
* can be charged to view these materials, unless express written
* permission is obtained from Bill Venners.
*
* d. The web pages and Java Applets may not be distributed on any
* media, other than a web server on a network, and may not accompany
* any book or publication.
*
* BILL VENNERS MAKES NO REPRESENTATIONS OR WARRANTIES ABOUT THE
* SUITABILITY OF THE SOFTWARE, EITHER EXPRESS OR IMPLIED, INCLUDING
* BUT NOT LIMITED TO THE IMPLIED WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR PARTICULAR PURPOSE, OR NON-INFRINGEMENT. BILL VENNERS
* SHALL NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY A LICENSEE AS A
* RESULT OF USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS
* DERIVATIVES.
*/
/**
* This class represents the garbage collected heap that is
* being exercised by this simulation. It contains all the
* logic for interacting with the heap.
*
* @author Bill Venners
*/
public class GCHeap {
private int handlePoolSize;
private int objectPoolSize;
private ObjectHandle[] handlePool;
private int[] objectPool;
GCHeap(int hndlPoolSize, int objPoolSize) {
handlePoolSize = hndlPoolSize;
objectPoolSize = objPoolSize;
objectPool = new int[objectPoolSize];
handlePool = new ObjectHandle[handlePoolSize];
// Initialize the object pool by putting a header at the zeroeth int location
// that indicates that the entire remainder of the object pool array is one
// big contiguous available memory block.
objectPool[0] = formMemBlockHeader(true, objectPoolSize);
for (int i = 0; i < handlePoolSize; ++i) {
handlePool[i] = new ObjectHandle();
handlePool[i].free = true;
}
}
// Returns number of handles in handlePool (2 ints each)
public int getHandlePoolSize() {
return handlePoolSize;
}
// Returns number of ints in object pool
public int getObjectPoolSize() {
return objectPoolSize;
}
public ObjectHandle getObjectHandle(int i) {
return handlePool[i - 1]; // Subtract one because zero is used to indicate null,
// so allocateHandle() adds 1 to the index.
}
public int getObjectPool(int i) {
return objectPool[i];
}
public void setObjectPool(int i, int value) {
objectPool[i] = value;
}
// formMemBlockHeader() makes an int that contains two pieces of information,
// the length of the memory block and whether the memory block is free. The int
// is the header for the block and is stored immediately before the block in
// the objectPool array. These headers form a kind of linked list of memory blocks
// because you can always jump to the next header by adding length to the index
// of the current blocks header to get index to the next block's header. The length
// variable is in units of ints; it tells how many ints long the memory block is,
// including the header int.
//
// The zeroeth bit of a memory block header is used to indicate freeness. If the bit
// is one, the memory block is free. Bits 1 through 31 are the memory block's length
// in number of ints.
private int formMemBlockHeader(boolean free, int length) {
int retVal = length << 1;
if (free) {
retVal |= 1;
}
return retVal;
}
// The length of a memory block includes the header int.
public int getMemBlockLength(int header) {
return header >> 1;
}
public boolean getMemBlockFree(int header) {
boolean retVal = false;
if ((header & 0x1) == 0x1) {
retVal = true;
}
return retVal;
}
// allocateObject() returns an int which is an index into the handlePool array. This is,
// in effect, a handle. Because a handle of zero indicates a null handle, the zeroeth int
// of the handlePool array is unused. The index returned by this function is a handle to
// the object.
//
// bytesNeeded -- number of bytes needed by the object for which memory is being
// allocated.
public int allocateObject(int bytesNeeded, FishIcon fish) {
// Initialize the return value to zero, which indicates not enough memory was
// available for the new object.
int retVal = 0;
// Because the objectPool is an array of ints, all objects are int aligned. Calculate
// the number of ints required by the new object based on the passed number of bytes
// required. This is done by adding 3 (sizeof(int) - 1) to the bytesNeeded and
// dividing by 4 (sizeof(int)). So one, two, three, and four byte objects will require
// one int. Five, six, seven, and eight byte objects will require two ints, etc...
int intsNeeded = (bytesNeeded + 3) / 4;
int i = 0;
while (i < objectPoolSize) {
int header = objectPool[i];
boolean free = false;
if (getMemBlockFree(header)) {
free = true;
}
int length = getMemBlockLength(header);
if (!free) {
// This memory block is not free, so continue by looking at the next memory
// block. Add length to the current index into the constant pool to get the
// index of the next memory block header.
i += length;
continue;
}
// We have found a free block. First, concatenate any other free blocks that may
// be contiguous to this one.
while ((i + length) < objectPoolSize && getMemBlockFree(objectPool[i + length])) {
// The next memory block is also free, so concatenate with the previous
// one. This is done by extending the size of the previous memory block
// to include the next block.
length += getMemBlockLength(objectPool[i + length]);
objectPool[i] = formMemBlockHeader(true, length);
}
// Now that we have a free block, check to see if it is big enough to hold
// the object for which the memory was requested.
if (length - 1 < intsNeeded) {
// This memory block is free, but not big enough for the fat object for
// which memory has been requested. So continue by looking at the next
// memory block. Add length to the current index into the constant pool
// to get the index of the next memory block header.
i += length;
continue;
}
// The current free block is big enough for our new object. First, check to see
// if there is more than enough memory in this block than that actually required
// by the new object.
int extraMem = length - intsNeeded - 1;
if (extraMem > 0) {
// The free block has more than enough memory, so we must split it into
// two blocks. The first block will be exactly the right size for our
// new object. The second will contain whatever is leftover. This splitting
// is accomplished by changing the length of the original header to exactly
// equal whatever is required by the new object, then adding a second
// header for the leftover memory.
objectPool[i] = formMemBlockHeader(true, intsNeeded + 1);
objectPool[i + intsNeeded + 1] = formMemBlockHeader(true, extraMem);
}
// At this point objectPool[i] is exactly the right size for the new object.
// All that we need to do now is allocate the handle to the memory. Add one
// to i before passing to allocHandle, because i currently points to the header.
// The object handle should point past the header at the start of the object
// itself.
retVal = allocateHandle(i + 1, fish);
if (retVal > 0) {
objectPool[i] = formMemBlockHeader(false, intsNeeded + 1);
}
break;
}
return retVal;
}
// allocateHandle() returns an int which is an index into the handlePool array. This is,
// in effect, a handle. Because a handle of zero indicates a null handle, the zeroeth int
// of the handlePool array is unused.
public int allocateHandle(int objectHandle, FishIcon fishHandle) {
int retVal = 0;
for (int i = 0; i < handlePoolSize; ++i) {
if (handlePool[i].free) {
handlePool[i].free = false;
handlePool[i].objectPos = objectHandle;
handlePool[i].fish = fishHandle;
retVal = i + 1; // Add one because zero means failure.
break;
}
}
return retVal;
}
public void freeObject(int handle) {
if (!handlePool[handle - 1].free) {
handlePool[handle - 1].free = true;
handlePool[handle - 1].fish = null;
int objectTableIndex = handlePool[handle - 1].objectPos;
int header = getObjectPool(objectTableIndex - 1);
int length = getMemBlockLength(header);
header = formMemBlockHeader(true, length);
setObjectPool(objectTableIndex - 1, header);
}
}
// Returns true if an object was slid
public boolean slideNextNonContiguousObjectDown() {
boolean retVal = false;
int i = 0;
while (i < objectPoolSize) {
int header = objectPool[i];
boolean free = false;
if (getMemBlockFree(header)) {
free = true;
}
int length = getMemBlockLength(header);
if (!free) {
// This memory block is not free, so continue by looking at the next memory
// block. Add length to the current index into the constant pool to get the
// index of the next memory block header.
i += length;
continue;
}
// We have found a free block. First, concatenate any other free blocks that may
// be contiguous to this one.
while ((i + length) < objectPoolSize && getMemBlockFree(objectPool[i + length])) {
// The next memory block is also free, so concatenate with the previous
// one. This is done by extending the size of the previous memory block
// to include the next block.
length += getMemBlockLength(objectPool[i + length]);
objectPool[i] = formMemBlockHeader(true, length);
}
// See if an object exists at the next location, if not break out of the loop
// and return false. There are no other objects that can be slid.
if (i + length >= objectPoolSize) {
break;
}
int sliderLength = getMemBlockLength(objectPool[i + length]);
for (int j = 1; j < sliderLength; ++j) {
objectPool[i + j] = objectPool[i + length + j];
}
objectPool[i] = formMemBlockHeader(false, sliderLength);
objectPool[i + sliderLength] = formMemBlockHeader(true, length);
for (int j = 0; j < handlePoolSize; ++j) {
if (!handlePool[j].free && handlePool[j].objectPos == i + length + 1) {
handlePool[j].objectPos = i + 1;
break;
}
}
retVal = true;
break;
}
return retVal;
}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -