зеркало из https://github.com/mozilla/gecko-dev.git
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:
Родитель
596b93e6f4
Коммит
0e9cbbecc9
|
@ -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[];
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
|
Загрузка…
Ссылка в новой задаче