memoryblockmanager.java
来自「纯java操作系统jnode,安装简单和操作简单的个人使用的Java操作系统」· Java 代码 · 共 252 行
JAVA
252 行
/*
* $Id: MemoryBlockManager.java,v 1.6 2004/02/15 11:06:48 epr Exp $
*/
package org.jnode.vm;
/**
* This class is used to allocate and free fixed size blocks of memory. This memory is not garbage
* collected, nor is each block addressable as a java object. Since this manager is used by the
* Object allocation, do not allocate object in this class.
*
* @author Ewout Prangsma (epr@users.sourceforge.net)
*/
public final class MemoryBlockManager extends VmSystemObject implements Uninterruptible {
/** Size of a memory block. */
static final int BLOCK_SIZE_SHIFT = 16;
static final int BLOCK_SIZEa = (1 << BLOCK_SIZE_SHIFT);
/** Inclusive start address of first block */
private static long startPtr;
/** Exclusive end address of last block */
private static long endPtr;
/** Address of lock to my structures */
private static Address lockPtr;
/** Address of usage bitmap */
private static Address bitmapPtr;
/** Total number of blocks */
private static long blockCount;
/** Has this class be initialized yet */
private static boolean initialized;
/** Number of allocated blocks */
private static long allocatedBlocks;
/** Number of next allocatable block */
private static long nextBlockNr;
/**
* Allocate a new block of memory at blockSize large. The actual size is aligned on BLOCK_SIZE.
*
* @param blockSize
* @return The address of the start of the block, or null when no memory is available.
*/
static final Address allocateBlock(int blockSize) {
if (!initialized) {
initialize();
}
enter();
try {
// Calculate the number of blocks needed
final int reqBlockCount = (int)(blockAlign(blockSize, true) >>> BLOCK_SIZE_SHIFT);
// Find a large enough series of blocks
final long nr = findFreeBlocks(reqBlockCount);
if (nr == -1L) {
//Unsafe.debug("ret null."); Unsafe.debug(blockSize);
//Unsafe.debug("allocated blocks"); Unsafe.debug(allocatedBlocks);
//Unsafe.debug("total blocks"); Unsafe.debug(blockCount);
//Unsafe.getCurrentProcessor().getArchitecture().getStackReader().debugStackTrace();
//Unsafe.die("allocateBlock");
return null;
}
// Mark all blocks as in use
for (int i = 0; i < reqBlockCount; i++) {
setInUse(nr + i, true);
}
// Return the address of block "nr".
allocatedBlocks += reqBlockCount;
nextBlockNr = nr + reqBlockCount;
return Unsafe.longToAddress(startPtr + (nr << BLOCK_SIZE_SHIFT));
} finally {
exit();
}
}
/**
* Free a previously allocated new block of memory at blockSize large.
* The actual size is aligned on BLOCK_SIZE.
*
* @param ptr The block address as returned by allocateBlock .
* @param blockSize The size of the block as given to allocateBlock.
*/
static final void freeBlock(Address ptr, int blockSize) {
enter();
try {
// Calculate the block number
final long nr = (Unsafe.addressToLong(ptr) - startPtr) >>> BLOCK_SIZE_SHIFT;
// Calculate the number of blocks
final long reqBlockCount = blockAlign(blockSize, true) >>> BLOCK_SIZE_SHIFT;
// Mark all blocks as free
for (long i = 0; i < reqBlockCount; i++) {
setInUse(nr + i, false);
}
allocatedBlocks -= reqBlockCount;
nextBlockNr = Math.min(nextBlockNr, nr);
} finally {
exit();
}
}
/**
* Gets the size of non-allocated memory blocks.
* @return The free size in bytes
*/
public static long getFreeMemory() {
return (blockCount - allocatedBlocks) << BLOCK_SIZE_SHIFT;
}
/**
* Find the first free memory block that is following by freeBlockCount-1 free memory blocks.
*
* @param freeBlockCount
* @return The block number of the first block, or -1 if not found.
*/
private static long findFreeBlocks(int freeBlockCount) {
final long max = blockCount;
long nr = nextBlockNr;
while (nr < max) {
boolean inUse = false;
int i;
for (i = 0; (i < freeBlockCount) && (!inUse); i++) {
inUse |= isInUse(nr + i);
}
if (!inUse) {
// We found it
return nr;
} else {
//Unsafe.debug("nr"); Unsafe.debug(nr);
//Unsafe.debug("i"); Unsafe.debug(i);
// We came across an used block
nr += (i + 1);
}
}
//Unsafe.debug("ret -1"); Unsafe.die();
return -1;
}
/**
* Is a block identified by it blockNr [0..blockCount-1] already used.
*
* @param blockNr
* @return boolean
*/
private static final boolean isInUse(long blockNr) {
final long offset = blockNr >>> 3; // we still need a byte offset
final int mask = (1 << (blockNr & 7));
final Address ptr = Unsafe.add(bitmapPtr, Unsafe.longToAddress(offset));
final int v = Unsafe.getByte(ptr) & 0xFF;
return ((v & mask) == mask);
}
/**
* Is a block identified by it blockNr [0..blockCount-1] already used.
*
* @param blockNr
*/
private static final void setInUse(long blockNr, boolean inUse) {
final long offset = blockNr >>> 3; // we still need a byte offset
final int mask = (1 << (blockNr & 7));
//final int mask = (1 << blockNr);
final Address ptr = Unsafe.add(bitmapPtr, Unsafe.longToAddress(offset));
int v = Unsafe.getByte(ptr);
if (inUse) {
v |= mask;
} else {
v &= ~mask;
}
Unsafe.setByte(ptr, (byte)v);
}
/**
* Initialize this manager.
*/
private final static void initialize() {
//Unsafe.debug("initialize.");
startPtr = blockAlign(Unsafe.addressToLong(Unsafe.getMemoryStart()), true);
endPtr = blockAlign(Unsafe.addressToLong(Unsafe.getMemoryEnd()), false);
final long size = endPtr - startPtr;
Unsafe.debug(size);
blockCount = (size >>> BLOCK_SIZE_SHIFT);
// Create a lock (4 bytes) and usage bitmap at the front of the memory region
final long rawBitmapSize = (blockCount >>> 3);
//final long rawBitmapSize = blockCount;
final long bitmapSize = blockAlign(4 + rawBitmapSize, true);
lockPtr = Unsafe.longToAddress(startPtr);
bitmapPtr = Unsafe.longToAddress(startPtr + 4);
// Clear the lock & bitmap size
clear(lockPtr, bitmapSize);
// Now shift the startptr.
startPtr += bitmapSize;
blockCount -= bitmapSize >>> BLOCK_SIZE_SHIFT;
allocatedBlocks = 0;
// Mark as initialized
initialized = true;
//Unsafe.debug("BitmapPtr "); Unsafe.debug(Unsafe.addressToLong(bitmapPtr));
//Unsafe.debug("LockPtr "); Unsafe.debug(Unsafe.addressToLong(lockPtr));
//Unsafe.debug("StartPtr "); Unsafe.debug(startPtr);
//Unsafe.debug("BitmapSize "); Unsafe.debug(bitmapSize);
//Unsafe.debug("Block count "); Unsafe.debug(blockCount);
//Unsafe.die();
//Unsafe.debug("end of initialize.");
}
/**
* Claim access to my structures. This is done without using java monitorenter/exit
* instructions, since they may need a memory allocation.
*/
private static final void enter() {
while (!Unsafe.atomicCompareAndSwap(lockPtr, 0, 1)) {
Unsafe.debug(Unsafe.getInt(lockPtr));
VmThread.yield();
}
}
/**
* Release access to my structures.
*/
private static final void exit() {
Unsafe.setInt(lockPtr, 0);
}
/**
* Align the given address on the boundary on BLOCK_SIZE.
*
* @param ptr
* @param roundup
* @return The aligned address as long
*/
private static long blockAlign(long ptr, boolean roundup) {
final long blockSizeM1 = BLOCK_SIZEa - 1;
if (roundup) {
ptr += blockSizeM1;
}
return ptr & ~blockSizeM1;
}
/**
* Clear a large area of memory. Fill the memory with zeros.
* @param ptr
* @param size
*/
private static void clear(Address ptr, long size) {
//Unsafe.debug("clear");
//Unsafe.debug(size);
while (size != 0) {
final int part = (int)Math.min(size, 0x7fffffffL);
//Unsafe.debug(size);
Unsafe.clear(ptr, part);
ptr = Unsafe.add(ptr, part);
size -= part;
}
}
}
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?