Various optimizations in the memory allocators as fix for bug 2254. Also now zap the contents of allocated and freed blocks.

This commit is contained in:
sfraser%netscape.com 1999-01-22 00:20:06 +00:00
Родитель 596b93e6f4
Коммит 0e9cbbecc9
10 изменённых файлов: 209 добавлений и 62 удалений

Просмотреть файл

@ -17,6 +17,7 @@
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <new.h> // for placement new
@ -162,6 +163,7 @@ void nsHeapZoneHeader::DisposeZonePtr(Ptr thePtr, Boolean &outWasLastChunk)
const SInt32 nsAllocatorManager::kNumMasterPointerBlocks = 30;
const SInt32 nsAllocatorManager::kApplicationStackSizeIncrease = (32 * 1024);
const SInt32 nsAllocatorManager::kHeapZoneHeapPercentage = 60;
const SInt32 nsAllocatorManager::kSmallHeapByteRange = 16;
nsAllocatorManager* nsAllocatorManager::sAllocatorManager = nil;
@ -174,11 +176,11 @@ nsAllocatorManager::nsAllocatorManager()
, mLastHeapZone(nil)
//--------------------------------------------------------------------
{
mMinSmallBlockSize = 44; // some magic numbers for now
mMinLargeBlockSize = 256;
mMinSmallBlockSize = 129; //128; //44; // some magic numbers for now
mMinLargeBlockSize = 256; //512; //256;
mNumFixedSizeAllocators = mMinSmallBlockSize / 4;
mNumSmallBlockAllocators = 1 + (mMinLargeBlockSize - mMinSmallBlockSize) / 4;
mNumSmallBlockAllocators = 1 + (mMinLargeBlockSize - mMinSmallBlockSize) / kSmallHeapByteRange;
//can't use new yet!
mFixedSizeAllocators = (nsMemAllocator **)NewPtrClear(mNumFixedSizeAllocators * sizeof(nsMemAllocator*));
@ -194,7 +196,7 @@ nsAllocatorManager::nsAllocatorManager()
mFixedSizeAllocators[i] = (nsMemAllocator *)NewPtr(sizeof(nsFixedSizeAllocator));
if (mFixedSizeAllocators[i] == nil)
throw((OSErr)memFullErr);
new (mFixedSizeAllocators[i]) nsFixedSizeAllocator((i + 1) * 4);
new (mFixedSizeAllocators[i]) nsFixedSizeAllocator(i * 4 + (i > 0) * 1, (i + 1) * 4);
}
for (SInt32 i = 0; i < mNumSmallBlockAllocators; i ++)
@ -202,14 +204,15 @@ nsAllocatorManager::nsAllocatorManager()
mSmallBlockAllocators[i] = (nsMemAllocator *)NewPtr(sizeof(nsSmallHeapAllocator));
if (mSmallBlockAllocators[i] == nil)
throw((OSErr)memFullErr);
new (mSmallBlockAllocators[i]) nsSmallHeapAllocator();
SInt32 minBytes = mMinSmallBlockSize + i * kSmallHeapByteRange; // lower bound of block size
new (mSmallBlockAllocators[i]) nsSmallHeapAllocator(minBytes, minBytes + kSmallHeapByteRange - 1);
}
mLargeAllocator = (nsMemAllocator *)NewPtr(sizeof(nsLargeHeapAllocator));
if (mLargeAllocator == nil)
throw((OSErr)memFullErr);
new (mLargeAllocator) nsLargeHeapAllocator();
new (mLargeAllocator) nsLargeHeapAllocator(mMinLargeBlockSize, 0x7FFFFFFF);
// make the heap zone for our subheaps
UInt32 heapZoneSize;
@ -258,7 +261,8 @@ nsMemAllocator* nsAllocatorManager::GetAllocatorForBlockSize(size_t blockSize)
return mFixedSizeAllocators[ (blockSize == 0) ? 0 : ((blockSize + 3) >> 2) - 1 ];
if (blockSize < mMinLargeBlockSize)
return mSmallBlockAllocators[ ((blockSize + 3) >> 2) - mNumFixedSizeAllocators ];
return mSmallBlockAllocators[ ((blockSize - mMinSmallBlockSize + kSmallHeapByteRange) / kSmallHeapByteRange) - 1 ];
//return mSmallBlockAllocators[ ((blockSize + (kSmallHeapByteRange - 1)) / kSmallHeapByteRange) - mNumFixedSizeAllocators ];
return mLargeAllocator;
}
@ -304,7 +308,8 @@ nsHeapZoneHeader* nsAllocatorManager::MakeNewHeapZone(Size zoneSize, Size minZon
// block size multiple. All blocks should be multiples of this size,
// to reduce heap fragmentation
const Size nsAllocatorManager::kChunkSizeMultiple = 2 * 1024;
const Size nsAllocatorManager::kMacMemoryPtrOvehead = 16; // this overhead is documented in IM:Memory 2-22
const Size nsAllocatorManager::kMaxChunkSize = 48 * 1024;
const Size nsAllocatorManager::kMacMemoryPtrOvehead = 16; // this overhead is documented in IM:Memory 2-22
const Size nsAllocatorManager::kTempMemHeapZoneSize = 1024 * 1024; // 1MB temp handles
const Size nsAllocatorManager::kTempMemHeapMinZoneSize = 256 * 1024; // min 256K handle
@ -318,7 +323,7 @@ Ptr nsAllocatorManager::AllocateSubheap(Size preferredSize, Size &outActualSize)
// calculate an ideal chunk size by rounding up
preferredSize = kChunkSizeMultiple * ((preferredSize + (kChunkSizeMultiple - 1)) / kChunkSizeMultiple);
// take into accound the memory manager's pointer overhead (16 btyes), to avoid fragmentation
// take into account the memory manager's pointer overhead (16 btyes), to avoid fragmentation
preferredSize += ((preferredSize / kChunkSizeMultiple) - 1) * kMacMemoryPtrOvehead;
outActualSize = preferredSize;
@ -332,7 +337,10 @@ Ptr nsAllocatorManager::AllocateSubheap(Size preferredSize, Size &outActualSize)
}
// we failed to allocate. Let's make a new heap zone
thisHeapZone = MakeNewHeapZone(kTempMemHeapZoneSize, kTempMemHeapMinZoneSize);
UInt32 prefZoneSize = preferredSize + sizeof(nsHeapZoneHeader) + 512; // for zone overhead
UInt32 zoneSize = (kTempMemHeapZoneSize > prefZoneSize) ? kTempMemHeapZoneSize : prefZoneSize;
UInt32 minZoneSize = (kTempMemHeapMinZoneSize > prefZoneSize) ? kTempMemHeapMinZoneSize : prefZoneSize;
thisHeapZone = MakeNewHeapZone(zoneSize, minZoneSize);
if (thisHeapZone)
return thisHeapZone->AllocateZonePtr(preferredSize);
@ -450,7 +458,6 @@ void nsAllocatorManager::DumpMemoryStats()
//--------------------------------------------------------------------
{
UInt32 i;
char outString[ 1024 ];
PRFileDesc *outFile;
// Enter a valid, UNIX-style full path on your system to get this
@ -461,6 +468,31 @@ void nsAllocatorManager::DumpMemoryStats()
return;
}
WriteString(outFile, "\n\n--------------------------------------------------------------------------------\n");
WriteString(outFile, "Max heap usage chart (* = 1024 bytes)\n");
WriteString(outFile, "--------------------------------------------------------------------------------\n\n");
UInt32 totHeapUsed = 0;
for (i = 0; i < mNumFixedSizeAllocators; i ++)
{
mFixedSizeAllocators[i]->DumpHeapUsage(outFile);
totHeapUsed += mFixedSizeAllocators[i]->GetMaxHeapUsage();
}
for (i = 0; i < mNumSmallBlockAllocators; i ++)
{
mSmallBlockAllocators[i]->DumpHeapUsage(outFile);
totHeapUsed += mSmallBlockAllocators[i]->GetMaxHeapUsage();
}
char outString[256];
sprintf(outString, "Total heap space used by allocators: %ldk\n", totHeapUsed / 1024);
WriteString(outFile, "--------------------------------------------------------------------------------\n");
WriteString(outFile, outString);
WriteString(outFile, "--------------------------------------------------------------------------------\n\n");
for (i = 0; i < mNumFixedSizeAllocators; i ++)
{
mFixedSizeAllocators[i]->DumpMemoryStats(outFile);
@ -492,7 +524,6 @@ void WriteString(PRFileDesc *file, const char * string)
#endif
#pragma mark -

Просмотреть файл

@ -103,7 +103,10 @@ class nsAllocatorManager
static const SInt32 kTempMemHeapMinZoneSize;
static const Size kChunkSizeMultiple;
static const Size kMaxChunkSize;
static const SInt32 kSmallHeapByteRange;
static nsAllocatorManager* GetAllocatorManager() { return sAllocatorManager ? sAllocatorManager : CreateAllocatorManager(); }
nsAllocatorManager();

Просмотреть файл

@ -26,9 +26,8 @@
const UInt32 FixedMemoryBlock::kFixedSizeBlockOverhead = sizeof(FixedMemoryBlockHeader) + MEMORY_BLOCK_TAILER_SIZE;
//--------------------------------------------------------------------
nsFixedSizeAllocator::nsFixedSizeAllocator(size_t blockSize)
: nsMemAllocator()
, mBlockSize(blockSize)
nsFixedSizeAllocator::nsFixedSizeAllocator(size_t minBlockSize, size_t maxBlockSize)
: nsMemAllocator(minBlockSize, maxBlockSize)
, mChunkWithSpace(nil)
//--------------------------------------------------------------------
{
@ -46,11 +45,11 @@ nsFixedSizeAllocator::~nsFixedSizeAllocator()
nsHeapChunk* nsFixedSizeAllocator::FindChunkWithSpace(size_t blockSize) const
//--------------------------------------------------------------------
{
nsFixedSizeHeapChunk* chunk = (nsFixedSizeHeapChunk *)mFirstChunk;
if (mChunkWithSpace && mChunkWithSpace->GetFreeList())
return mChunkWithSpace;
nsFixedSizeHeapChunk* chunk = (nsFixedSizeHeapChunk *)mFirstChunk;
// Try to find an existing chunk with a free block.
while (chunk != nil)
{
@ -84,9 +83,11 @@ void *nsFixedSizeAllocator::AllocatorMakeBlock(size_t blockSize)
blockHeader->SetHeaderTag(kUsedBlockHeaderTag);
blockHeader->SetTrailerTag(GetAllocatorBlockSize(), kUsedBlockTrailerTag);
blockHeader->ZapBlockContents(blockSize, kUsedMemoryFillPattern);
UInt32 paddedSize = (blockSize + 3) & ~3;
blockHeader->SetPaddingBytes(paddedSize - blockSize);
blockHeader->FillPaddingBytes(mBlockSize);
blockHeader->FillPaddingBytes(mMaxBlockSize);
#endif
#if STATS_MAC_MEMORY
@ -107,7 +108,9 @@ void nsFixedSizeAllocator::AllocatorFreeBlock(void *freeBlock)
#if DEBUG_HEAP_INTEGRITY
MEM_ASSERT(blockHeader->HasHeaderTag(kUsedBlockHeaderTag), "Bad block header");
MEM_ASSERT(blockHeader->GetTrailerTag(GetAllocatorBlockSize()) == kUsedBlockTrailerTag, "Bad block trailer");
MEM_ASSERT(blockHeader->CheckPaddingBytes(mBlockSize), "Block bounds have been overwritten");
MEM_ASSERT(blockHeader->CheckPaddingBytes(GetAllocatorBlockSize()), "Block bounds have been overwritten");
blockHeader->ZapBlockContents(GetAllocatorBlockSize(), kFreeMemoryFillPattern);
#endif
#if STATS_MAC_MEMORY
@ -128,6 +131,7 @@ void nsFixedSizeAllocator::AllocatorFreeBlock(void *freeBlock)
{
if (chunk == mChunkWithSpace)
mChunkWithSpace = nil;
FreeChunk(chunk);
}
else
@ -142,7 +146,7 @@ void *nsFixedSizeAllocator::AllocatorResizeBlock(void *block, size_t newSize)
//--------------------------------------------------------------------
{
// let blocks shrink to at most 16 bytes below this allocator's block size
if (newSize > mBlockSize || newSize <= mBlockSize - kMaxBlockResizeSlop)
if (newSize > mMaxBlockSize || newSize <= mMaxBlockSize - kMaxBlockResizeSlop)
return nil;
FixedMemoryBlock* blockHeader = FixedMemoryBlock::GetBlockHeader(block);
@ -150,14 +154,14 @@ void *nsFixedSizeAllocator::AllocatorResizeBlock(void *block, size_t newSize)
#if DEBUG_HEAP_INTEGRITY
MEM_ASSERT(blockHeader->HasHeaderTag(kUsedBlockHeaderTag), "Bad block header");
MEM_ASSERT(blockHeader->GetTrailerTag(GetAllocatorBlockSize()) == kUsedBlockTrailerTag, "Bad block trailer");
MEM_ASSERT(blockHeader->CheckPaddingBytes(mBlockSize), "Block bounds have been overwritten");
MEM_ASSERT(blockHeader->CheckPaddingBytes(mMaxBlockSize), "Block bounds have been overwritten");
// if we shrunk the block to below this allocator's normal size range, then these
// padding bytes won't be any use. But they are tested using mBlockSize, so we
// have to udpate them anyway.
UInt32 paddedSize = (newSize + 3) & ~3;
blockHeader->SetPaddingBytes(paddedSize - newSize);
blockHeader->FillPaddingBytes(mBlockSize);
blockHeader->FillPaddingBytes(mMaxBlockSize);
#endif
#if STATS_MAC_MEMORY
@ -173,7 +177,7 @@ void *nsFixedSizeAllocator::AllocatorResizeBlock(void *block, size_t newSize)
size_t nsFixedSizeAllocator::AllocatorGetBlockSize(void *thisBlock)
//--------------------------------------------------------------------
{
return mBlockSize;
return mMaxBlockSize;
}
@ -183,7 +187,13 @@ nsHeapChunk *nsFixedSizeAllocator::AllocateChunk(size_t requestedBlockSize)
//--------------------------------------------------------------------
{
Size actualChunkSize;
// adapt the chunk size if we have already allocated a number of chunks, and it's not above a max size
if (mNumChunks > 4 && mBaseChunkSize < nsAllocatorManager::kMaxChunkSize)
mBaseChunkSize *= 2;
Ptr chunkMemory = nsAllocatorManager::GetAllocatorManager()->AllocateSubheap(mBaseChunkSize, actualChunkSize);
if (!chunkMemory) return nil;
// use placement new to initialize the chunk in the memory block
nsHeapChunk *newHeapChunk = new (chunkMemory) nsFixedSizeHeapChunk(this, actualChunkSize);

Просмотреть файл

@ -15,6 +15,7 @@
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
* Reserved. */
#include <string.h>
class nsMemAllocator;
class nsFixedSizeHeapChunk;
@ -67,6 +68,12 @@ struct FixedMemoryBlock
}
UInt32 GetPaddingBytes() { return blockHeader.blockPadding; }
void ZapBlockContents(UInt32 blockSize, UInt8 pattern)
{
memset(&memory, pattern, blockSize);
}
// inline, so won't crash if this is a bad block
Boolean HasHeaderTag(MemoryBlockTag inHeaderTag)
{ return blockHeader.header.headerTag == inHeaderTag; }
@ -106,7 +113,7 @@ class nsFixedSizeAllocator : public nsMemAllocator
public:
nsFixedSizeAllocator(size_t blockSize);
nsFixedSizeAllocator(size_t minBlockSize, size_t maxBlockSize);
~nsFixedSizeAllocator();
virtual void * AllocatorMakeBlock(size_t blockSize);
@ -119,7 +126,7 @@ class nsFixedSizeAllocator : public nsMemAllocator
virtual nsHeapChunk* FindChunkWithSpace(size_t blockSize) const;
UInt32 GetAllocatorBlockSize() { return mBlockSize; }
UInt32 GetAllocatorBlockSize() { return mMaxBlockSize; }
protected:
@ -127,9 +134,6 @@ class nsFixedSizeAllocator : public nsMemAllocator
kMaxBlockResizeSlop = 16
};
UInt32 mBlockSize; // upper bound for blocks allocated in this heap
// does not include block overhead
nsFixedSizeHeapChunk *mChunkWithSpace; // cheap optimization

Просмотреть файл

@ -26,8 +26,8 @@
const UInt32 LargeBlockHeader::kLargeBlockOverhead = sizeof(LargeBlockHeader) + MEMORY_BLOCK_TAILER_SIZE;
//--------------------------------------------------------------------
nsLargeHeapAllocator::nsLargeHeapAllocator()
: nsMemAllocator()
nsLargeHeapAllocator::nsLargeHeapAllocator(size_t minBlockSize, size_t maxBlockSize)
: nsMemAllocator(minBlockSize, maxBlockSize)
//--------------------------------------------------------------------
{
mBaseChunkSize = mTempChunkSize = (64 * 1024);
@ -127,6 +127,8 @@ void nsLargeHeapAllocator::AllocatorFreeBlock(void *freeBlock)
MEM_ASSERT(blockHeader->HasHeaderTag(kUsedBlockHeaderTag), "Bad block header on free");
MEM_ASSERT(blockHeader->HasTrailerTag(blockHeader->GetBlockSize(), kUsedBlockTrailerTag), "Bad block trailer on free");
MEM_ASSERT(blockHeader->CheckPaddingBytes(), "Block overwrote bounds");
blockHeader->ZapBlockContents(kFreeMemoryFillPattern);
#endif
#if STATS_MAC_MEMORY
@ -168,6 +170,7 @@ nsHeapChunk *nsLargeHeapAllocator::AllocateChunk(size_t requestedBlockSize)
chunkSize = paddedBlockSize;
Ptr chunkMemory = nsAllocatorManager::GetAllocatorManager()->AllocateSubheap(chunkSize, actualChunkSize);
if (!chunkMemory) return nil;
// use placement new to initialize the chunk in the memory block
nsHeapChunk *newHeapChunk = new (chunkMemory) nsLargeHeapChunk(this, actualChunkSize);
@ -238,6 +241,7 @@ LargeBlockHeader* nsLargeHeapChunk::GetSpaceForBlock(UInt32 blockSize)
UInt32 allocSize = ((blockSize + 3) & ~3) + LargeBlockHeader::kLargeBlockOverhead;
if (allocSize > mTotalFree) return nil;
//Boolean expectFailure = (allocSize > mTotalFree);
/* scan through the blocks in this chunk looking for a big enough free block */
/* we never allocate the head block */
@ -280,12 +284,14 @@ LargeBlockHeader* nsLargeHeapChunk::GetSpaceForBlock(UInt32 blockSize)
blockHeader->SetHeaderTag(kUsedBlockHeaderTag);
blockHeader->SetTrailerTag(blockHeader->GetBlockSize(), kUsedBlockTrailerTag);
blockHeader->SetPaddingBytes(((blockSize + 3) & ~3) - blockSize);
blockHeader->ZapBlockContents(kUsedMemoryFillPattern);
blockHeader->FillPaddingBytes();
#endif
mTotalFree -= blockHeader->GetBlockHeapUsageSize();
IncrementUsedBlocks();
//MEM_ASSERT(!expectFailure, "I though this would fail!");
return blockHeader;
}

Просмотреть файл

@ -15,6 +15,7 @@
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
* Reserved. */
#include <string.h>
class nsMemAllocator;
class nsLargeHeapChunk;
@ -66,6 +67,8 @@ struct LargeBlockHeader
}
UInt32 GetPaddingBytes() { return paddingBytes; }
void ZapBlockContents(UInt8 pattern) { memset(&memory, pattern, GetBlockSize()); }
// inline, so won't crash if this is a bad block
Boolean HasHeaderTag(MemoryBlockTag inHeaderTag)
{ return header.headerTag == inHeaderTag; }
@ -108,7 +111,7 @@ class nsLargeHeapAllocator : public nsMemAllocator
public:
nsLargeHeapAllocator();
nsLargeHeapAllocator(size_t minBlockSize, size_t maxBlockSize);
~nsLargeHeapAllocator();

Просмотреть файл

@ -47,9 +47,12 @@ nsHeapChunk::~nsHeapChunk()
#pragma mark -
//--------------------------------------------------------------------
nsMemAllocator::nsMemAllocator()
nsMemAllocator::nsMemAllocator(size_t minBlockSize, size_t maxBlockSize)
: mFirstChunk(nil)
, mLastChunk(nil)
, mNumChunks(0)
, mMinBlockSize(minBlockSize)
, mMaxBlockSize(maxBlockSize)
#if DEBUG_HEAP_INTEGRITY
, mSignature(kMemAllocatorSignature)
#endif
@ -115,6 +118,8 @@ void nsMemAllocator::AddToChunkList(nsHeapChunk *inNewChunk)
mLastChunk = inNewChunk;
mNumChunks ++;
#if STATS_MAC_MEMORY
mCurSubheapCount ++;
if (mCurSubheapCount > mMaxSubheapCount)
@ -158,6 +163,8 @@ void nsMemAllocator::RemoveFromChunkList(nsHeapChunk *inChunk)
mLastChunk = prevChunk;
}
mNumChunks --;
#if STATS_MAC_MEMORY
mCurSubheapCount --;
@ -206,6 +213,31 @@ void nsMemAllocator::AccountForFreedBlock(size_t logicalSize)
mCurBlockSpaceUsed -= logicalSize;
}
//--------------------------------------------------------------------
void nsMemAllocator::DumpHeapUsage(PRFileDesc *outFile)
//--------------------------------------------------------------------
{
char outString[ 1024 ];
sprintf(outString, "%04ld ", mMaxBlockSize);
WriteString(outFile, outString);
char *p = outString;
SInt32 numStars = mMaxHeapSpaceUsed / 1024;
if (numStars > 1021)
numStars = 1021;
for (SInt32 i = 0; i < numStars; i ++)
*p++ = '*';
if (numStars == 1021)
*p++ = 'É';
*p++ = '\n';
*p = '\0';
WriteString(outFile, outString);
}
//--------------------------------------------------------------------
void nsMemAllocator::DumpMemoryStats(PRFileDesc *outFile)
@ -213,8 +245,10 @@ void nsMemAllocator::DumpMemoryStats(PRFileDesc *outFile)
{
char outString[ 1024 ];
sprintf(outString, "Stats for heap of blocks %ld - %ld bytes\n", mMinBlockSize, mMaxBlockSize);
WriteString ( outFile, "\n\n--------------------------------------------------------------------------------\n" );
WriteString(outFile, "Stats for heap\n");
WriteString(outFile, outString);
WriteString ( outFile, "--------------------------------------------------------------------------------\n" );
WriteString ( outFile, " Current Max\n" );
WriteString ( outFile, " ---------- -------\n" );

Просмотреть файл

@ -33,8 +33,8 @@ enum {
kUsedBlockTrailerTag = 'used',
kRefdBlockHeaderTag = 'REFD',
kRefdBlockTrailerTag = 'refd',
kFreeMemoryFillPattern = 0xEF,
kUsedMemoryFillPattern = 0xDB
kUsedMemoryFillPattern = 0xDB,
kFreeMemoryFillPattern = 0xEF //if you don't want to crash hard, change to 0x04 or 0x05,
};
@ -131,7 +131,7 @@ class nsMemAllocator
{
public:
nsMemAllocator();
nsMemAllocator(size_t minBlockSize, size_t maxBlockSize);
virtual ~nsMemAllocator() = 0;
static size_t GetBlockSize(void *thisBlock);
@ -171,9 +171,15 @@ class nsMemAllocator
nsHeapChunk *mFirstChunk; // pointer to first subheap managed by this allocator
nsHeapChunk *mLastChunk; // pointer to last subheap managed by this allocator
UInt32 mMinBlockSize; // smallest block normally handled by this allocator (inclusive)
UInt32 mMaxBlockSize; // largest block handled by this allocator (inclusive)
UInt32 mNumChunks; // number of chunks in list
UInt32 mBaseChunkSize; // size of subheap allocated at startup
UInt32 mTempChunkSize; // size of additional subheaps
#if STATS_MAC_MEMORY
public:
@ -183,6 +189,9 @@ class nsMemAllocator
void AccountForResizedBlock(size_t oldLogicalSize, size_t newLogicalSize);
void DumpMemoryStats(PRFileDesc *statsFile);
void DumpHeapUsage(PRFileDesc *statsFile);
UInt32 GetMaxHeapUsage() { return mMaxHeapSpaceUsed; }
private:

Просмотреть файл

@ -27,11 +27,13 @@ const UInt32 SmallHeapBlock::kBlockOverhead = sizeof(SmallHeapBlock) + MEMORY_BL
//--------------------------------------------------------------------
nsSmallHeapAllocator::nsSmallHeapAllocator()
: nsMemAllocator()
nsSmallHeapAllocator::nsSmallHeapAllocator(size_t minBlockSize, size_t maxBlockSize)
: nsMemAllocator(minBlockSize, maxBlockSize)
, mChunkWithSpace(nil)
//--------------------------------------------------------------------
{
mBaseChunkSize = mTempChunkSize = (nsAllocatorManager::kChunkSizeMultiple);
// this gets rounded up when we allocate chunks
mBaseChunkSize = mTempChunkSize = 64 * (mMaxBlockSize + SmallHeapBlock::kBlockOverhead); //(nsAllocatorManager::kChunkSizeMultiple);
}
//--------------------------------------------------------------------
@ -45,6 +47,13 @@ nsSmallHeapAllocator::~nsSmallHeapAllocator()
void *nsSmallHeapAllocator::AllocatorMakeBlock(size_t blockSize)
//--------------------------------------------------------------------
{
// try the cheap way first
if (mChunkWithSpace)
{
void *foundBlock = mChunkWithSpace->GetSpaceForBlock(blockSize);
if (foundBlock) return foundBlock;
}
nsSmallHeapChunk *chunk = (nsSmallHeapChunk *)mFirstChunk;
// walk through all of our chunks, trying to allocate memory from somewhere
@ -61,6 +70,7 @@ void *nsSmallHeapAllocator::AllocatorMakeBlock(size_t blockSize)
chunk = (nsSmallHeapChunk *)AllocateChunk(blockSize);
if (!chunk) return nil;
mChunkWithSpace = chunk;
return chunk->GetSpaceForBlock(blockSize);
}
@ -75,6 +85,8 @@ void nsSmallHeapAllocator::AllocatorFreeBlock(void *freeBlock)
MEM_ASSERT(deadBlock->HasHeaderTag(kUsedBlockHeaderTag), "Bad block header on free");
MEM_ASSERT(deadBlock->HasTrailerTag(deadBlock->GetBlockSize(), kUsedBlockTrailerTag), "Bad block trailer on free");
MEM_ASSERT(deadBlock->CheckPaddingBytes(), "Block has overwritten its bounds");
deadBlock->ZapBlockContents(kFreeMemoryFillPattern);
#endif
nsSmallHeapChunk *chunk = deadBlock->GetOwningChunk();
@ -88,7 +100,16 @@ void nsSmallHeapAllocator::AllocatorFreeBlock(void *freeBlock)
// if this chunk is completely empty and it's not the first chunk then free it
if (chunk->IsEmpty() && chunk!= mFirstChunk)
{
if (chunk == mChunkWithSpace)
mChunkWithSpace = nil;
FreeChunk(chunk);
}
else
{
mChunkWithSpace = chunk; // we know is has some space now, probably
}
}
@ -148,6 +169,7 @@ nsHeapChunk *nsSmallHeapAllocator::AllocateChunk(size_t blockSize)
Size actualChunkSize;
Ptr chunkMemory = nsAllocatorManager::GetAllocatorManager()->AllocateSubheap(mBaseChunkSize, actualChunkSize);
if (!chunkMemory) return nil;
// use placement new to initialize the chunk in the memory block
nsHeapChunk *newHeapChunk = new (chunkMemory) nsSmallHeapChunk(this, actualChunkSize);
@ -176,9 +198,10 @@ void nsSmallHeapAllocator::FreeChunk(nsHeapChunk *chunkToFree)
//--------------------------------------------------------------------
nsSmallHeapChunk::nsSmallHeapChunk(
nsMemAllocator *inOwningAllocator,
Size heapSize) :
nsHeapChunk(inOwningAllocator, heapSize),
mOverflow(nil)
Size heapSize)
: nsHeapChunk(inOwningAllocator, heapSize)
, mOverflow(nil)
, mTotalFree(0)
//--------------------------------------------------------------------
{
// init the bin ptrs
@ -215,6 +238,9 @@ nsSmallHeapChunk::nsSmallHeapChunk(
newRawBlockTrailer->SetOwningChunk(nil);
AddBlockToFreeList(newFreeOverflowBlock);
#if DEBUG_HEAP_INTEGRITY
mInitialFree = mTotalFree;
#endif
}
@ -222,6 +248,7 @@ nsSmallHeapChunk::nsSmallHeapChunk(
nsSmallHeapChunk::~nsSmallHeapChunk()
//--------------------------------------------------------------------
{
MEM_ASSERT(mUsedBlocks != 0 || mTotalFree == mInitialFree, "Bad free measure");
}
@ -233,6 +260,9 @@ void *nsSmallHeapChunk::GetSpaceForBlock(size_t blockSize)
UInt32 roundedBlockSize = (blockSize + 3) & ~3;
MEM_ASSERT(roundedBlockSize <= nsSmallHeapChunk::kMaximumBlockSize, "Block is too big for this allocator!");
if (mTotalFree < roundedBlockSize) return nil;
//Boolean expectFailure = (mTotalFree < roundedBlockSize);
// Try to find the best fit in one of the bins.
UInt32 startingBinNum = (roundedBlockSize - kDefaultSmallHeadMinSize) >> 2;
@ -341,6 +371,7 @@ done:
#if DEBUG_HEAP_INTEGRITY
allocatedBlock->SetHeaderTag(kUsedBlockHeaderTag);
allocatedBlock->SetTrailerTag(allocatedBlock->GetBlockSize(), kUsedBlockTrailerTag);
allocatedBlock->ZapBlockContents(kUsedMemoryFillPattern);
allocatedBlock->SetPaddingBytes(roundedBlockSize - blockSize);
allocatedBlock->FillPaddingBytes();
#endif
@ -350,6 +381,8 @@ done:
GetOwningAllocator()->AccountForNewBlock(blockSize);
#endif
//MEM_ASSERT(!expectFailure, "I though this would fail!");
IncrementUsedBlocks();
return &allocatedBlock->memory;
}
@ -574,17 +607,16 @@ void nsSmallHeapChunk::RemoveBlockFromFreeList(SmallHeapBlock *removeBlock)
else
{
UInt32 nextBlockBin = (blockSize - kDefaultSmallHeadMinSize) >> 2;
#if DEBUG_HEAP_INTEGRITY
if (blockSize < kDefaultSmallHeadMinSize)
DebugStr("\pBad block size");
if (nextBlockBin >= kDefaultSmallHeapBins)
DebugStr("\pBad bin index");
#endif
MEM_ASSERT(blockSize >= kDefaultSmallHeadMinSize, "Bad block size");
MEM_ASSERT(nextBlockBin < kDefaultSmallHeapBins, "Bad bin index");
mBins[nextBlockBin] = nextFree;
}
}
removeBlock->SetBlockUsed();
mTotalFree -= removeBlock->GetBlockHeapUsage();
}
@ -593,6 +625,8 @@ void nsSmallHeapChunk::RemoveBlockFromFreeList(SmallHeapBlock *removeBlock)
void nsSmallHeapChunk::AddBlockToFreeList(SmallHeapBlock *addBlock)
//--------------------------------------------------------------------
{
mTotalFree += addBlock->GetBlockHeapUsage();
addBlock->SetBlockUnused();
UInt32 blockSize = addBlock->GetBlockSize();
@ -609,12 +643,10 @@ void nsSmallHeapChunk::AddBlockToFreeList(SmallHeapBlock *addBlock)
else
{
UInt32 nextBlockBin = (blockSize - kDefaultSmallHeadMinSize) >> 2;
#if DEBUG_HEAP_INTEGRITY
if (blockSize < kDefaultSmallHeadMinSize)
DebugStr("\pBad block size");
if (nextBlockBin >= kDefaultSmallHeapBins)
DebugStr("\pBad bin index");
#endif
MEM_ASSERT(blockSize >= kDefaultSmallHeadMinSize, "Bad block size");
MEM_ASSERT(nextBlockBin < kDefaultSmallHeapBins, "Bad bin index");
SmallHeapBlock *tempBlock = mBins[nextBlockBin];
addBlock->SetNextFree(tempBlock);
if (tempBlock) tempBlock->SetPrevFree(addBlock);

Просмотреть файл

@ -15,6 +15,7 @@
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
* Reserved. */
#include <string.h>
class nsMemAllocator;
class nsSmallHeapChunk;
@ -66,14 +67,18 @@ struct SmallHeapBlock
*lastLong &= ~mask;
*lastLong |= (mask & kBlockPaddingBytes);
}
Boolean CheckPaddingBytes() {
UInt32 padding = blockFlags & kBlockPaddingMask;
long *lastLong = (long *)((char *)&memory + blockSize - sizeof(long));
UInt32 mask = (1 << (8 * padding)) - 1;
return (*lastLong & mask) == (mask & kBlockPaddingBytes);
}
UInt32 GetPaddingBytes() { return (blockFlags & kBlockPaddingMask); }
void ZapBlockContents(UInt8 pattern) { memset(&memory, pattern, blockSize); }
// inline, so won't crash if this is a bad block
Boolean HasHeaderTag(MemoryBlockTag inHeaderTag)
{ return info.inUseInfo.freeProc.headerTag == inHeaderTag; }
@ -130,7 +135,7 @@ class nsSmallHeapAllocator : public nsMemAllocator
public:
nsSmallHeapAllocator();
nsSmallHeapAllocator(size_t minBlockSize, size_t maxBlockSize);
~nsSmallHeapAllocator();
virtual void * AllocatorMakeBlock(size_t blockSize);
@ -144,7 +149,7 @@ class nsSmallHeapAllocator : public nsMemAllocator
protected:
nsSmallHeapChunk* mChunkWithSpace; // cheap optimization
};
@ -167,20 +172,30 @@ class nsSmallHeapChunk : public nsHeapChunk
enum {
kDefaultSmallHeadMinSize = 4L,
kDefaultSmallHeapBins = 64L,
kDefaultSmallHeapBins = 128L,
kMaximumBinBlockSize = kDefaultSmallHeadMinSize + 4L * kDefaultSmallHeapBins - 1,
kMaximumBlockSize = 0xFFFF
};
SmallHeapBlock** GetBins(UInt32 binIndex) { return mBins + binIndex; }
SmallHeapBlock** GetBins(UInt32 binIndex)
{
MEM_ASSERT(binIndex < kDefaultSmallHeapBins, "Bad bin index!");
return mBins + binIndex;
}
SmallHeapBlock* GetOverflow() { return mOverflow; }
void RemoveBlockFromFreeList(SmallHeapBlock *removeBlock);
void AddBlockToFreeList(SmallHeapBlock *addBlock);
SmallHeapBlock *mOverflow;
SmallHeapBlock *mBins[kDefaultSmallHeapBins];
UInt32 mTotalFree;
#if DEBUG
UInt32 mInitialFree;
#endif
SmallHeapBlock* mOverflow;
SmallHeapBlock* mBins[kDefaultSmallHeapBins];
SmallHeapBlock mMemory[];
};