Dumping out my latest memory manager changes. Still not being built yet. New code includes stats collection, but no way to write out stats at the moment.

This commit is contained in:
sfraser%netscape.com 1998-12-04 02:21:19 +00:00
Родитель 36f4bf7247
Коммит 6b88bb2485
9 изменённых файлов: 375 добавлений и 110 удалений

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

@ -25,7 +25,6 @@
#include <Processes.h>
#include <CodeFragments.h>
#include "nsMemAllocator.h"
#include "nsFixedSizeAllocator.h"
@ -59,7 +58,7 @@ class nsAllocatorManager
static const SInt32 kNumMasterPointerBlocks;
static const SInt32 kApplicationStackSizeIncrease;
static const SInt32 kHeapZoneHeapPercentage;
nsAllocatorManager();
~nsAllocatorManager();
@ -88,6 +87,9 @@ class nsAllocatorManager
nsMemAllocator** mSmallBlockAllocators; // array of pointers to allocator objects
nsMemAllocator* mLargeAllocator;
THz mHeapZone; // the heap zone for our memory heaps
};
//--------------------------------------------------------------------
@ -96,6 +98,7 @@ class nsAllocatorManager
const SInt32 nsAllocatorManager::kNumMasterPointerBlocks = 30;
const SInt32 nsAllocatorManager::kApplicationStackSizeIncrease = (32 * 1024);
const SInt32 nsAllocatorManager::kHeapZoneHeapPercentage = 60;
nsAllocatorManager* nsAllocatorManager::sAllocatorManager = nil;
@ -126,9 +129,6 @@ nsAllocatorManager::nsAllocatorManager() :
mFixedSizeAllocators[i] = (nsMemAllocator *)NewPtr(sizeof(nsFixedSizeAllocator));
if (mFixedSizeAllocators[i] == nil)
throw((OSErr)memFullErr);
// placement new
new (mFixedSizeAllocators[i]) nsFixedSizeAllocator((i + 1) * 4);
}
for (SInt32 i = 0; i < mNumSmallBlockAllocators; i ++)
@ -136,16 +136,42 @@ nsAllocatorManager::nsAllocatorManager() :
mSmallBlockAllocators[i] = (nsMemAllocator *)NewPtr(sizeof(nsSmallHeapAllocator));
if (mSmallBlockAllocators[i] == nil)
throw((OSErr)memFullErr);
// placement new
new (mSmallBlockAllocators[i]) nsSmallHeapAllocator();
}
mLargeAllocator = (nsMemAllocator *)NewPtr(sizeof(nsLargeHeapAllocator));
if (mLargeAllocator == nil)
throw((OSErr)memFullErr);
// placement new
new (mLargeAllocator) nsLargeHeapAllocator();
// make the heap zone for our subheaps
UInt32 heapZoneSize;
heapZoneSize = ( kHeapZoneHeapPercentage * ::FreeMem() ) / 100;
heapZoneSize = ( ( heapZoneSize + 3 ) & ~3 ); // round up to a multiple of 4 bytes
Ptr heapZone = ::NewPtr(heapZoneSize);
if (heapZone == nil)
throw((OSErr)memFullErr);
#define kNumMasterPointers 24 // does not matter, since we won't be allocating handles
// in this heap zone
Ptr endZone = heapZone + heapZoneSize;
::InitZone(nil, kNumMasterPointers, endZone, heapZone);
// set the current zone back to the application zone
::SetZone(::ApplicationZone());
mHeapZone = (THz)heapZone;
// now we have the heap zone, call (placement) new on our allocators
for (SInt32 i = 0; i < mNumFixedSizeAllocators; i ++)
new (mFixedSizeAllocators[i]) nsFixedSizeAllocator(mHeapZone, (i + 1) * 4);
for (SInt32 i = 0; i < mNumSmallBlockAllocators; i ++)
new (mSmallBlockAllocators[i]) nsSmallHeapAllocator(mHeapZone);
new (mLargeAllocator) nsLargeHeapAllocator(mHeapZone);
}
//--------------------------------------------------------------------
@ -182,10 +208,11 @@ nsMemAllocator* nsAllocatorManager::GetAllocatorForBlockSize(size_t blockSize)
{
if (blockSize < mMinSmallBlockSize)
return mFixedSizeAllocators[ (blockSize == 0) ? 0 : ((blockSize + 3) >> 2) - 1 ];
else if (blockSize < mMinLargeBlockSize)
if (blockSize < mMinLargeBlockSize)
return mSmallBlockAllocators[ ((blockSize + 3) >> 2) - mNumFixedSizeAllocators ];
else
return mLargeAllocator;
return mLargeAllocator;
}
@ -223,6 +250,7 @@ nsMemAllocator* nsAllocatorManager::GetAllocatorForBlockSize(size_t blockSize)
}
catch (...)
{
return paramErr;
}
return noErr;
@ -320,6 +348,8 @@ void *calloc(size_t nele, size_t elesize)
#pragma mark -
#if 0
/*----------------------------------------------------------------------------
__MemInitialize
@ -332,8 +362,12 @@ pascal OSErr __MemInitialize(const CFragInitBlock *theInitBlock)
OSErr err = __initialize(theInitBlock);
if (err != noErr) return err;
return nsAllocatorManager::InitializeMacMemory(nsAllocatorManager::kNumMasterPointerBlocks,
nsAllocatorManager::kApplicationStackSizeIncrease);
#if __profile__
if (ProfilerInit(collectDetailed, bestTimeBase, 500, 20) != noErr)
ExitToShell();
#endif
return noErr;
}
@ -350,6 +384,14 @@ pascal OSErr __MemInitialize(const CFragInitBlock *theInitBlock)
pascal void __MemTerminate(void)
{
#if __profile__
ProfilerDump("\pMemory Tester.prof");
ProfilerTerm();
#endif
__terminate();
}
#endif

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

@ -25,8 +25,9 @@
const UInt32 FixedMemoryBlock::kFixedSizeBlockOverhead = sizeof(FixedMemoryBlockHeader) + MEMORY_BLOCK_TAILER_SIZE;
//--------------------------------------------------------------------
nsFixedSizeAllocator::nsFixedSizeAllocator(size_t blockSize) :
mBlockSize(blockSize)
nsFixedSizeAllocator::nsFixedSizeAllocator(THz heapZone, size_t blockSize)
: nsMemAllocator(heapZone)
, mBlockSize(blockSize)
//--------------------------------------------------------------------
{
mBaseChunkSize = mTempChunkSize = (nsMemAllocator::kChunkSizeMultiple);
@ -46,9 +47,9 @@ nsHeapChunk* nsFixedSizeAllocator::FindChunkWithSpace(size_t blockSize) const
nsFixedSizeHeapChunk* chunk = (nsFixedSizeHeapChunk *)mFirstChunk;
// Try to find an existing chunk with a free block.
while ( chunk != NULL )
while (chunk != nil)
{
if ( chunk->GetFreeList() != nil )
if (chunk->GetFreeList() != nil)
return chunk;
chunk = (nsFixedSizeHeapChunk *)chunk->GetNextChunk();
@ -71,16 +72,21 @@ void *nsFixedSizeAllocator::AllocatorMakeBlock(size_t blockSize)
}
FixedMemoryBlock* blockHeader = chunk->FetchFirstFree();
// these get stripped by the compiler in optimized builds
#if DEBUG_HEAP_INTEGRITY
blockHeader->SetHeaderTag(kUsedBlockHeaderTag);
blockHeader->SetTrailerTag(GetAllocatorBlockSize(), kUsedBlockTrailerTag);
#if DEBUG_HEAP_INTEGRITY
UInt32 paddedSize = (blockSize + 3) & ~3;
blockHeader->SetPaddingBytes(paddedSize - blockSize);
blockHeader->FillPaddingBytes(mBlockSize);
#endif
#if STATS_MAC_MEMORY
blockHeader->blockHeader.header.logicalBlockSize = blockSize;
AccountForNewBlock(blockSize);
#endif
return (void *)&blockHeader->memory;
}
@ -91,15 +97,22 @@ void nsFixedSizeAllocator::AllocatorFreeBlock(void *freeBlock)
{
FixedMemoryBlock* blockHeader = FixedMemoryBlock::GetBlockHeader(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");
#endif
#if STATS_MAC_MEMORY
AccountForFreedBlock(blockHeader->blockHeader.header.logicalBlockSize);
#endif
nsFixedSizeHeapChunk* chunk = blockHeader->GetOwningChunk();
// these get stripped by the compiler in optimized builds
#if DEBUG_HEAP_INTEGRITY
blockHeader->SetHeaderTag(kFreeBlockHeaderTag);
blockHeader->SetTrailerTag(GetAllocatorBlockSize(), kFreeBlockTrailerTag);
#endif
chunk->ReturnToFreeList(blockHeader);
@ -121,11 +134,11 @@ void *nsFixedSizeAllocator::AllocatorResizeBlock(void *block, size_t newSize)
FixedMemoryBlock* blockHeader = FixedMemoryBlock::GetBlockHeader(block);
#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");
#if DEBUG_HEAP_INTEGRITY
// 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.
@ -133,7 +146,12 @@ void *nsFixedSizeAllocator::AllocatorResizeBlock(void *block, size_t newSize)
blockHeader->SetPaddingBytes(paddedSize - newSize);
blockHeader->FillPaddingBytes(mBlockSize);
#endif
#if STATS_MAC_MEMORY
AccountForResizedBlock(blockHeader->blockHeader.header.logicalBlockSize, newSize);
blockHeader->blockHeader.header.logicalBlockSize = newSize;
#endif
return block;
}

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

@ -83,16 +83,6 @@ struct FixedMemoryBlock
MemoryBlockTrailer *trailer = (MemoryBlockTrailer *)((char *)&memory + blockSize);
return trailer->trailerTag;
}
#else
// stubs
void SetPaddingBytes(UInt32 padding) {}
void FillPaddingBytes(UInt32 blockSize)
Boolean CheckPaddingBytes(UInt32 blockSize) { return true; }
UInt32 GetPaddingBytes() { return 0; }
Boolean HasHeaderTag(MemoryBlockTag inHeaderTag){ return true; }
void SetHeaderTag(MemoryBlockTag inHeaderTag){}
void SetTrailerTag(UInt32 blockSize, MemoryBlockTag theTag) {}
MemoryBlockTag GetTrailerTag(UInt32 blockSize) { return 0; }
#endif
static const UInt32 kFixedSizeBlockOverhead;
@ -116,7 +106,7 @@ class nsFixedSizeAllocator : public nsMemAllocator
public:
nsFixedSizeAllocator(size_t blockSize);
nsFixedSizeAllocator(THz heapZone, size_t blockSize);
~nsFixedSizeAllocator();
virtual void * AllocatorMakeBlock(size_t blockSize);

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

@ -25,7 +25,8 @@
const UInt32 LargeBlockHeader::kLargeBlockOverhead = sizeof(LargeBlockHeader) + MEMORY_BLOCK_TAILER_SIZE;
//--------------------------------------------------------------------
nsLargeHeapAllocator::nsLargeHeapAllocator()
nsLargeHeapAllocator::nsLargeHeapAllocator(THz heapZone)
: nsMemAllocator(heapZone)
//--------------------------------------------------------------------
{
mBaseChunkSize = mTempChunkSize = (64 * 1024);
@ -68,6 +69,12 @@ void * nsLargeHeapAllocator::AllocatorMakeBlock(size_t blockSize)
if (theBlock)
{
theBlock->SetLogicalSize(blockSize);
#if STATS_MAC_MEMORY
theBlock->header.logicalBlockSize = blockSize; // yes, it is stored in 2 places in this allocator
AccountForNewBlock(blockSize);
#endif
return &(theBlock->memory);
}
@ -79,6 +86,32 @@ void * nsLargeHeapAllocator::AllocatorMakeBlock(size_t blockSize)
void *nsLargeHeapAllocator::AllocatorResizeBlock(void *block, size_t newSize)
//--------------------------------------------------------------------
{
LargeBlockHeader *blockHeader = LargeBlockHeader::GetBlockHeader(block);
nsLargeHeapChunk *chunk = blockHeader->GetOwningChunk();
#if DEBUG_HEAP_INTEGRITY
MEM_ASSERT(blockHeader->HasHeaderTag(kUsedBlockHeaderTag), "Bad block header on realloc");
MEM_ASSERT(blockHeader->HasTrailerTag(blockHeader->GetBlockSize(), kUsedBlockTrailerTag), "Bad block trailer on realloc");
MEM_ASSERT(blockHeader->CheckPaddingBytes(), "Block has overwritten its bounds");
#endif
UInt32 newAllocSize = (newSize + 3) & ~3;
// we can resize this block to any size, provided it fits.
if (newAllocSize < blockHeader->GetBlockSize()) // shrinking
{
return chunk->ShrinkBlock(blockHeader, newSize);
}
else if (newAllocSize > blockHeader->GetBlockSize()) // growing
{
return chunk->GrowBlock(blockHeader, newSize);
}
else
{
return chunk->ResizeBlockInPlace(blockHeader, newSize);
}
return nil;
}
@ -87,14 +120,25 @@ void *nsLargeHeapAllocator::AllocatorResizeBlock(void *block, size_t newSize)
void nsLargeHeapAllocator::AllocatorFreeBlock(void *freeBlock)
//--------------------------------------------------------------------
{
LargeBlockHeader *blockHeader = (LargeBlockHeader *)((char *)freeBlock - sizeof(LargeBlockHeader));
LargeBlockHeader *blockHeader = LargeBlockHeader::GetBlockHeader(freeBlock);
#if DEBUG_HEAP_INTEGRITY
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");
nsLargeHeapChunk *chunk = blockHeader->GetOwningChunk();
#endif
#if STATS_MAC_MEMORY
AccountForFreedBlock(blockHeader->header.logicalBlockSize);
#endif
nsLargeHeapChunk *chunk = blockHeader->GetOwningChunk();
chunk->ReturnBlock(blockHeader);
#if DEBUG_HEAP_INTEGRITY
blockHeader->SetHeaderTag(kFreeBlockHeaderTag);
#endif
// if this chunk is completely empty and it's not the first chunk then free it
if (chunk->IsEmpty() && chunk != mFirstChunk)
FreeChunk(chunk);
@ -178,7 +222,7 @@ nsLargeHeapChunk::nsLargeHeapChunk(
freeBlock->SetPrevBlock(nil);
freeBlock->SetNextBlock( (LargeBlockHeader *) ( (UInt32)freeBlock + heapSize - 2 * LargeBlockHeader::kLargeBlockOverhead) );
// and then a zero sized allcated block at the end
// and then a zero sized allocated block at the end
mTail = freeBlock->GetNextBlock();
mTail->SetNextBlock(nil);
mTail->SetPrevBlock(freeBlock);
@ -198,6 +242,8 @@ LargeBlockHeader* nsLargeHeapChunk::GetSpaceForBlock(UInt32 blockSize)
{
UInt32 allocSize = ((blockSize + 3) & ~3) + LargeBlockHeader::kLargeBlockOverhead;
if (allocSize > mTotalFree) return nil;
/* scan through the blocks in this chunk looking for a big enough free block */
/* we never allocate the head block */
LargeBlockHeader *prevBlock = GetHeadBlock();
@ -235,10 +281,12 @@ LargeBlockHeader* nsLargeHeapChunk::GetSpaceForBlock(UInt32 blockSize)
blockHeader->SetPrevBlock(prevBlock);
blockHeader->SetOwningChunk(this);
#if DEBUG_HEAP_INTEGRITY
blockHeader->SetHeaderTag(kUsedBlockHeaderTag);
blockHeader->SetTrailerTag(blockHeader->GetBlockSize(), kUsedBlockTrailerTag);
blockHeader->SetPaddingBytes(((blockSize + 3) & ~3) - blockSize);
blockHeader->FillPaddingBytes();
#endif
mTotalFree -= blockHeader->GetBlockHeapUsageSize();
IncrementUsedBlocks();
@ -267,6 +315,9 @@ void *nsLargeHeapChunk::GrowBlock(LargeBlockHeader *growBlock, size_t newSize)
return nil;
// grow this block
#if STATS_MAC_MEMORY
UInt32 oldLogicalSize = growBlock->GetLogicalSize();
#endif
MEM_ASSERT(growBlock->logicalSize < newSize, "Wrong block size on grow block");
growBlock->SetLogicalSize(newSize);
@ -281,6 +332,9 @@ void *nsLargeHeapChunk::GrowBlock(LargeBlockHeader *growBlock, size_t newSize)
smallFree->GetNextBlock()->SetPrevBlock(smallFree);
growBlock->SetNextBlock(smallFree);
mTotalFree += smallFree->GetBlockHeapUsageSize();
#if DEBUG_HEAP_INTEGRITY
smallFree->header.headerTag = kFreeBlockHeaderTag;
#endif
}
else
{
@ -288,8 +342,17 @@ void *nsLargeHeapChunk::GrowBlock(LargeBlockHeader *growBlock, size_t newSize)
freeBlock->GetNextBlock()->SetPrevBlock(growBlock);
}
return (void *)(&growBlock->memory);
#if DEBUG_HEAP_INTEGRITY
growBlock->SetTrailerTag(growBlock->GetBlockSize(), kUsedBlockTrailerTag);
growBlock->SetPaddingBytes(((newSize + 3) & ~3) - newSize);
growBlock->FillPaddingBytes();
#endif
#if STATS_MAC_MEMORY
GetOwningAllocator()->AccountForResizedBlock(oldLogicalSize, newSize);
#endif
return (void *)(&growBlock->memory);
}
@ -305,7 +368,10 @@ void *nsLargeHeapChunk::ShrinkBlock(LargeBlockHeader *growBlock, size_t newSize)
LargeBlockHeader* smallFree = nil; // Where the recovered freeblock will go
// shrink this block
MEM_ASSERT(growBlock->logicalSize > newSize, "Wrong bock size on shrink block");
#if STATS_MAC_MEMORY
UInt32 oldLogicalSize = growBlock->GetLogicalSize();
#endif
MEM_ASSERT(oldAllocSize > newAllocSize, "Wrong bock size on shrink block");
growBlock->SetLogicalSize(newSize);
// is the block following this block a free block?
@ -335,9 +401,42 @@ void *nsLargeHeapChunk::ShrinkBlock(LargeBlockHeader *growBlock, size_t newSize)
#endif
}
#if DEBUG_HEAP_INTEGRITY
growBlock->SetTrailerTag(growBlock->GetBlockSize(), kUsedBlockTrailerTag);
growBlock->SetPaddingBytes(((newSize + 3) & ~3) - newSize);
growBlock->FillPaddingBytes();
#endif
#if STATS_MAC_MEMORY
GetOwningAllocator()->AccountForResizedBlock(oldLogicalSize, newSize);
#endif
return (void *)(&growBlock->memory);
}
//--------------------------------------------------------------------
void* nsLargeHeapChunk::ResizeBlockInPlace(LargeBlockHeader *theBlock, size_t newSize)
//--------------------------------------------------------------------
{
theBlock->SetLogicalSize(newSize);
#if DEBUG_HEAP_INTEGRITY
UInt32 newAllocSize = (newSize + 3) & ~3;
theBlock->SetPaddingBytes(newAllocSize - newSize);
theBlock->FillPaddingBytes();
#endif
#if STATS_MAC_MEMORY
GetOwningAllocator()->AccountForResizedBlock(theBlock->header.logicalBlockSize, newSize);
theBlock->header.logicalBlockSize = newSize;
#endif
return (void *)(&theBlock->memory);
}
//--------------------------------------------------------------------
void nsLargeHeapChunk::ReturnBlock(LargeBlockHeader *deadBlock)
//--------------------------------------------------------------------

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

@ -23,6 +23,8 @@ class nsLargeHeapChunk;
struct LargeBlockHeader
{
static LargeBlockHeader *GetBlockHeader(void *block) { return (LargeBlockHeader *)((char *)block - sizeof(LargeBlockHeader)); }
Boolean IsFreeBlock() { return prev == nil; }
UInt32 GetBlockSize() { return ((UInt32)next - (UInt32)this - kLargeBlockOverhead); }
@ -79,16 +81,6 @@ struct LargeBlockHeader
MemoryBlockTrailer *trailer = (MemoryBlockTrailer *)((char *)&memory + blockSize);
return (trailer->trailerTag == theTag);
}
#else
// stubs
void SetPaddingBytes(UInt32 padding) {}
void FillPaddingBytes()
Boolean CheckPaddingBytes() { return true; }
UInt32 GetPaddingBytes() { return 0; }
Boolean HasHeaderTag(MemoryBlockTag inHeaderTag){ return true; }
void SetHeaderTag(MemoryBlockTag inHeaderTag){}
void SetTrailerTag(UInt32 blockSize, MemoryBlockTag theTag) {}
Boolean HasTrailerTag(UInt32 blockSize, MemoryBlockTag theTag) { return true; }
#endif
static const UInt32 kLargeBlockOverhead;
@ -116,7 +108,7 @@ class nsLargeHeapAllocator : public nsMemAllocator
public:
nsLargeHeapAllocator();
nsLargeHeapAllocator(THz heapZone);
~nsLargeHeapAllocator();
@ -154,6 +146,7 @@ class nsLargeHeapChunk : public nsHeapChunk
void * GrowBlock(LargeBlockHeader *growBlock, size_t newSize);
void * ShrinkBlock(LargeBlockHeader *shrinkBlock, size_t newSize);
void * ResizeBlockInPlace(LargeBlockHeader *theBlock, size_t newSize);
void ReturnBlock(LargeBlockHeader *deadBlock);

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

@ -20,7 +20,6 @@
#include "nsMemAllocator.h"
//--------------------------------------------------------------------
nsHeapChunk::nsHeapChunk(nsMemAllocator *inOwningAllocator, Size heapSize, Handle tempMemHandle)
: mOwningAllocator(inOwningAllocator)
@ -47,15 +46,15 @@ nsHeapChunk::~nsHeapChunk()
#pragma mark -
//--------------------------------------------------------------------
nsMemAllocator::nsMemAllocator()
: mFirstChunk(nil)
nsMemAllocator::nsMemAllocator(THz inHeapZone)
: mHeapZone(inHeapZone)
, mFirstChunk(nil)
, mLastChunk(nil)
#if DEBUG_HEAP_INTEGRITY
, mSignature(kMemAllocatorSignature)
#endif
//--------------------------------------------------------------------
{
}
//--------------------------------------------------------------------
@ -73,8 +72,10 @@ nsMemAllocator::~nsMemAllocator()
//--------------------------------------------------------------------
{
MemoryBlockHeader *blockHeader = MemoryBlockHeader::GetHeaderFromBlock(thisBlock);
#if DEBUG_HEAP_INTEGRITY
MEM_ASSERT(blockHeader->HasHeaderTag(kUsedBlockHeaderTag), "Bad block header tag");
MEM_ASSERT(blockHeader->owningChunk->IsGoodChunk(), "Block has bad chunk pointer");
#endif
return (blockHeader->owningChunk->GetOwningAllocator());
}
@ -83,7 +84,9 @@ nsMemAllocator::~nsMemAllocator()
//--------------------------------------------------------------------
{
nsMemAllocator* allocator = GetAllocatorFromBlock(thisBlock);
#if DEBUG_HEAP_INTEGRITY
MEM_ASSERT(allocator && allocator->IsGoodAllocator(), "Failed to get allocator for block");
#endif
return allocator->AllocatorGetBlockSize(thisBlock);
}
@ -101,6 +104,12 @@ void nsMemAllocator::AddToChunkList(nsHeapChunk *inNewChunk)
mFirstChunk = inNewChunk;
mLastChunk = inNewChunk;
#if STATS_MAC_MEMORY
mCurSubheapCount ++;
if (mCurSubheapCount > mMaxSubheapCount)
mMaxSubheapCount = mCurSubheapCount;
#endif
}
@ -134,6 +143,10 @@ void nsMemAllocator::RemoveFromChunkList(nsHeapChunk *inChunk)
if (mLastChunk == thisChunk)
mLastChunk = prevChunk;
}
#if STATS_MAC_MEMORY
mCurSubheapCount --;
#endif
}
@ -144,6 +157,7 @@ const Size nsMemAllocator::kFreeHeapSpace = 512 * 1024;
// block size multiple. All blocks should be multiples of this size,
// to reduce heap fragmentation
const Size nsMemAllocator::kChunkSizeMultiple = 2 * 1024;
const Size nsMemAllocator::kMacMemoryPtrOvehead = 16;
//--------------------------------------------------------------------
Ptr nsMemAllocator::DoMacMemoryAllocation(Size preferredSize, Size &outActualSize,
@ -160,28 +174,27 @@ Ptr nsMemAllocator::DoMacMemoryAllocation(Size preferredSize, Size &outActualSiz
// than preferredSize
//--------------------------------------------------------------------
{
*outTempMemHandle = nil;
// calculate an ideal chunk size by rounding up
//preferredSize += kChunkSizeMultiple * ((preferredSize % kChunkSizeMultiple) > 0);
preferredSize = kChunkSizeMultiple * (((preferredSize % kChunkSizeMultiple) > 0) + preferredSize / kChunkSizeMultiple);
preferredSize = kChunkSizeMultiple * ((preferredSize + (kChunkSizeMultiple - 1)) / kChunkSizeMultiple);
// take into accound the memory manager's pointer overhead (16 btyes), to avoid fragmentation
preferredSize += ((preferredSize / kChunkSizeMultiple) - 1) * kMacMemoryPtrOvehead;
outActualSize = preferredSize;
// Get the space available if a purge happened. This does not do the purge (despite the name)
long total, contig;
::PurgeSpace(&total, &contig);
// try to allocate in our heap zone
::SetZone(mHeapZone);
Ptr resultPtr = ::NewPtr(preferredSize);
// set the current zone back to the application zone
::SetZone(::ApplicationZone());
if (resultPtr != nil)
return resultPtr;
Ptr resultPtr = nil;
if (contig + preferredSize > kFreeHeapSpace) // space in heap
{
resultPtr = ::NewPtr(preferredSize);
if (resultPtr != nil)
return resultPtr;
}
// try temp mem now
// that failed, so try temp mem now
OSErr err;
Handle tempMemHandle = ::TempNewHandle(preferredSize, &err);
if (tempMemHandle != nil)
@ -195,3 +208,42 @@ Ptr nsMemAllocator::DoMacMemoryAllocation(Size preferredSize, Size &outActualSiz
}
#if STATS_MAC_MEMORY
//--------------------------------------------------------------------
void nsMemAllocator::AccountForNewBlock(size_t logicalSize)
//--------------------------------------------------------------------
{
mCurBlockCount ++;
if (mCurBlockCount > mMaxBlockCount)
mMaxBlockCount = mCurBlockCount;
mCurBlockSpaceUsed += logicalSize;
if (mCurBlockSpaceUsed > mMaxBlockSpaceUsed)
mMaxBlockSpaceUsed = mCurBlockSpaceUsed;
}
//--------------------------------------------------------------------
void nsMemAllocator::AccountForResizedBlock(size_t oldLogicalSize, size_t newLogicalSize)
//--------------------------------------------------------------------
{
mCurBlockSpaceUsed -= oldLogicalSize;
mCurBlockSpaceUsed += newLogicalSize;
if (mCurBlockSpaceUsed > mMaxBlockSpaceUsed)
mMaxBlockSpaceUsed = mCurBlockSpaceUsed;
}
//--------------------------------------------------------------------
void nsMemAllocator::AccountForFreedBlock(size_t logicalSize)
//--------------------------------------------------------------------
{
mCurBlockCount --;
mCurBlockSpaceUsed -= logicalSize;
}
#endif

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

@ -16,12 +16,7 @@
* Reserved. */
// temporary defines
//#define DEBUG_MAC_MEMORY 0
//#define TRACK_EACH_ALLOCATOR 0
//#define DEBUG_HEAP_INTEGRITY DEBUG
//#define STATS_MAC_MEMORY 0
#include <stddef.h>
class nsMemAllocator;
class nsHeapChunk;
@ -45,6 +40,13 @@ typedef UInt32 MemoryBlockTag;
struct MemoryBlockHeader
{
nsHeapChunk *owningChunk;
#if STATS_MAC_MEMORY
// it sucks putting an extra data member in here which affects stats, but there is no other
// way to store the logical size of each block.
size_t logicalBlockSize;
#endif
#if DEBUG_HEAP_INTEGRITY
//MemoryBlockHeader *next;
//MemoryBlockHeader *prev;
@ -106,7 +108,7 @@ class nsHeapChunk
protected:
#if DEBUG_HEAP_INTEGRITY
enum {
kChunkSignature = 'oink'
kChunkSignature = 'Chnk'
};
OSType mSignature;
@ -128,8 +130,8 @@ class nsMemAllocator
{
public:
nsMemAllocator();
virtual ~nsMemAllocator();
nsMemAllocator(THz inHeapZone);
virtual ~nsMemAllocator() = 0;
static size_t GetBlockSize(void *thisBlock);
static nsMemAllocator* GetAllocatorFromBlock(void *thisBlock);
@ -156,6 +158,7 @@ class nsMemAllocator
static const Size kFreeHeapSpace;
static const Size kChunkSizeMultiple;
static const Size kMacMemoryPtrOvehead;
Ptr DoMacMemoryAllocation(Size preferredSize, Size &outActualSize, Handle *outTempMemHandle);
@ -163,22 +166,54 @@ class nsMemAllocator
void RemoveFromChunkList(nsHeapChunk *inChunk);
enum {
kMemAllocatorSignature = 'ARSE'
kMemAllocatorSignature = 'ARSE' // Allocators R Supremely Efficient
};
#if DEBUG_HEAP_INTEGRITY
OSType mSignature; // signature for debugging
#endif
#if DEBUG_BLOCK_TRACKING
AllocationSet *mAllocationSet; // allocation set used by xp_tracker code
#endif
nsHeapChunk *mFirstChunk; // pointer to first subheap managed by this allocator
nsHeapChunk *mLastChunk; // pointer to last subheap managed by this allocator
UInt32 mBaseChunkSize; // size of subheap allocated at startup
UInt32 mTempChunkSize; // size of additional subheaps
THz mHeapZone; // heap zone in which to allocate pointers
#if STATS_MAC_MEMORY
public:
void AccountForNewBlock(size_t logicalSize);
void AccountForFreedBlock(size_t logicalSize);
void AccountForResizedBlock(size_t oldLogicalSize, size_t newLogicalSize);
private:
UInt32 mCurBlockCount; // number of malloc blocks allocated now
UInt32 mMaxBlockCount; // max number of malloc blocks allocated
UInt32 mCurBlockSpaceUsed; // sum of logical size of allocated blocks
UInt32 mMaxBlockSpaceUsed; // max of sum of logical size of allocated blocks
UInt32 mCurHeapSpaceUsed; // sum of physical size of allocated chunks
UInt32 mMaxHeapSpaceUsed; // max of sum of logical size of allocated chunks
UInt32 mCurSubheapCount; // current number of subheaps allocated by this allocator
UInt32 mMaxSubheapCount; // max number of subheaps allocated by this allocator
// the difference between mCurBlockSpaceUsed and mCurHeapSpaceUsed is
// the allocator overhead, which consists of:
//
// 1. Block overhead (rounding, headers & trailers)
// 2. Unused block space in chunks
// 3. Chunk overhead (rounding, headers & trailers)
//
// This is a reasonable measure of the space efficiency of these allocators
#endif
};

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

@ -26,7 +26,8 @@ const UInt32 SmallHeapBlock::kBlockOverhead = sizeof(SmallHeapBlock) + MEMORY_BL
//--------------------------------------------------------------------
nsSmallHeapAllocator::nsSmallHeapAllocator()
nsSmallHeapAllocator::nsSmallHeapAllocator(THz heapZone)
: nsMemAllocator(heapZone)
//--------------------------------------------------------------------
{
mBaseChunkSize = mTempChunkSize = (nsMemAllocator::kChunkSizeMultiple);
@ -69,14 +70,18 @@ void nsSmallHeapAllocator::AllocatorFreeBlock(void *freeBlock)
{
SmallHeapBlock *deadBlock = SmallHeapBlock::GetBlockHeader(freeBlock);
#if DEBUG_HEAP_INTEGRITY
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");
#endif
nsSmallHeapChunk *chunk = deadBlock->GetOwningChunk();
#if DEBUG_HEAP_INTEGRITY
deadBlock->SetHeaderTag(kFreeBlockHeaderTag);
deadBlock->SetTrailerTag(deadBlock->GetBlockSize(), kFreeBlockTrailerTag);
#endif
chunk->ReturnBlock(deadBlock);
@ -93,9 +98,11 @@ void *nsSmallHeapAllocator::AllocatorResizeBlock(void *block, size_t newSize)
SmallHeapBlock *blockHeader = SmallHeapBlock::GetBlockHeader(block);
nsSmallHeapChunk *chunk = blockHeader->GetOwningChunk();
#if DEBUG_HEAP_INTEGRITY
MEM_ASSERT(blockHeader->HasHeaderTag(kUsedBlockHeaderTag), "Bad block header on realloc");
MEM_ASSERT(blockHeader->HasTrailerTag(blockHeader->GetBlockSize(), kUsedBlockTrailerTag), "Bad block trailer on realloc");
MEM_ASSERT(blockHeader->CheckPaddingBytes(), "Block has overwritten its bounds");
#endif
UInt32 newAllocSize = (newSize + 3) & ~3;
@ -111,13 +118,7 @@ void *nsSmallHeapAllocator::AllocatorResizeBlock(void *block, size_t newSize)
}
else
{
// adjust padding
#if DEBUG_HEAP_INTEGRITY
blockHeader->SetPaddingBytes(newAllocSize - newSize);
blockHeader->FillPaddingBytes();
#endif
return block; // stays same size
return chunk->ResizeBlockInPlace(blockHeader, newSize);
}
return nil;
@ -129,7 +130,9 @@ size_t nsSmallHeapAllocator::AllocatorGetBlockSize(void *thisBlock)
//--------------------------------------------------------------------
{
SmallHeapBlock *allocBlock = SmallHeapBlock::GetBlockHeader(thisBlock);
#if DEBUG_HEAP_INTEGRITY
MEM_ASSERT(allocBlock->HasHeaderTag(kUsedBlockHeaderTag), "Bad block header on get block size");
#endif
return allocBlock->GetBlockSize();
}
@ -343,14 +346,18 @@ done:
allocatedBlock->SetOwningChunk(this);
#if DEBUG_HEAP_INTEGRITY
allocatedBlock->SetHeaderTag(kUsedBlockHeaderTag);
allocatedBlock->SetTrailerTag(allocatedBlock->GetBlockSize(), kUsedBlockTrailerTag);
#if DEBUG_HEAP_INTEGRITY
allocatedBlock->SetPaddingBytes(roundedBlockSize - blockSize);
allocatedBlock->FillPaddingBytes();
#endif
#if STATS_MAC_MEMORY
allocatedBlock->SetLogicalBlockSize(blockSize);
GetOwningAllocator()->AccountForNewBlock(blockSize);
#endif
IncrementUsedBlocks();
return &allocatedBlock->memory;
}
@ -421,8 +428,13 @@ void *nsSmallHeapChunk::GrowBlock(SmallHeapBlock *growBlock, size_t newSize)
#if DEBUG_HEAP_INTEGRITY
growBlock->SetPaddingBytes(newAllocSize - newSize);
growBlock->FillPaddingBytes();
#endif
growBlock->SetTrailerTag(growBlock->GetBlockSize(), kUsedBlockTrailerTag);
#endif
#if STATS_MAC_MEMORY
GetOwningAllocator()->AccountForResizedBlock(growBlock->GetLogicalBlockSize(), newSize);
growBlock->SetLogicalBlockSize(newSize);
#endif
return (void *)(&growBlock->memory);
}
@ -480,13 +492,38 @@ void *nsSmallHeapChunk::ShrinkBlock(SmallHeapBlock *shrinkBlock, size_t newSize)
#if DEBUG_HEAP_INTEGRITY
shrinkBlock->SetPaddingBytes(newAllocSize - newSize);
shrinkBlock->FillPaddingBytes();
#endif
shrinkBlock->SetTrailerTag(shrinkBlock->GetBlockSize(), kUsedBlockTrailerTag);
#endif
#if STATS_MAC_MEMORY
GetOwningAllocator()->AccountForResizedBlock(shrinkBlock->GetLogicalBlockSize(), newSize);
shrinkBlock->SetLogicalBlockSize(newSize);
#endif
return (void *)(&shrinkBlock->memory);
}
//--------------------------------------------------------------------
void* nsSmallHeapChunk::ResizeBlockInPlace(SmallHeapBlock *theBlock, size_t newSize)
//--------------------------------------------------------------------
{
#if DEBUG_HEAP_INTEGRITY
UInt32 newAllocSize = (newSize + 3) & ~3;
theBlock->SetPaddingBytes(newAllocSize - newSize);
theBlock->FillPaddingBytes();
#endif
#if STATS_MAC_MEMORY
GetOwningAllocator()->AccountForResizedBlock(theBlock->GetLogicalBlockSize(), newSize);
theBlock->SetLogicalBlockSize(newSize);
#endif
return (void *)(&theBlock->memory);
}
//--------------------------------------------------------------------
void nsSmallHeapChunk::ReturnBlock(SmallHeapBlock *deadBlock)
//--------------------------------------------------------------------
@ -494,6 +531,10 @@ void nsSmallHeapChunk::ReturnBlock(SmallHeapBlock *deadBlock)
SmallHeapBlock *nextBlock = deadBlock->GetNextBlock();
SmallHeapBlock *prevBlock = deadBlock->GetPrevBlock();
#if STATS_MAC_MEMORY
GetOwningAllocator()->AccountForFreedBlock(deadBlock->GetLogicalBlockSize());
#endif
// If the block after us is free, then coalesce with it.
if (! nextBlock->IsBlockUsed())
{

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

@ -91,18 +91,13 @@ struct SmallHeapBlock
MemoryBlockTrailer *trailer = (MemoryBlockTrailer *)((char *)&memory + blockSize);
return (trailer->trailerTag == theTag);
}
#else
// stubs
void SetPaddingBytes(UInt32 padding) {}
void FillPaddingBytes()
Boolean CheckPaddingBytes() { return true; }
UInt32 GetPaddingBytes() { return 0; }
Boolean HasHeaderTag(MemoryBlockTag inHeaderTag){ return true; }
void SetHeaderTag(MemoryBlockTag inHeaderTag){}
void SetTrailerTag(UInt32 blockSize, MemoryBlockTag theTag) {}
Boolean HasTrailerTag(UInt32 blockSize, MemoryBlockTag theTag) { return true; }
#endif
#if STATS_MAC_MEMORY
size_t GetLogicalBlockSize() { return info.inUseInfo.freeProc.logicalBlockSize; }
void SetLogicalBlockSize(size_t blockSize) { info.inUseInfo.freeProc.logicalBlockSize = blockSize; }
#endif
private:
SmallHeapBlock *prevBlock;
@ -135,7 +130,7 @@ class nsSmallHeapAllocator : public nsMemAllocator
public:
nsSmallHeapAllocator();
nsSmallHeapAllocator(THz heapZone);
~nsSmallHeapAllocator();
virtual void * AllocatorMakeBlock(size_t blockSize);
@ -168,7 +163,7 @@ class nsSmallHeapChunk : public nsHeapChunk
void * GrowBlock(SmallHeapBlock *growBlock, size_t newSize);
void * ShrinkBlock(SmallHeapBlock *shrinkBlock, size_t newSize);
void * ResizeBlockInPlace(SmallHeapBlock *shrinkBlock, size_t newSize);
protected: