Allocators now use shared heap zones, for better temp mem use. Other minor changes.

This commit is contained in:
sfraser%netscape.com 1998-12-05 22:04:36 +00:00
parent 5e512d94a3
commit 8de3b16eb4
10 changed files with 528 additions and 209 deletions

View File

@ -16,6 +16,7 @@
* Reserved. */
#include <stdlib.h>
#include <string.h>
#include <new.h> // for placement new
@ -25,6 +26,10 @@
#include <Processes.h>
#include <CodeFragments.h>
#if __profile__
#include <Profiler.h>
#endif
#include "nsMemAllocator.h"
#include "nsFixedSizeAllocator.h"
@ -52,48 +57,106 @@ pascal void __MemTerminate(void);
//--------------------------------------------------------------------
class nsAllocatorManager
nsHeapZoneHeader::nsHeapZoneHeader(Ptr zonePtr, Size ptrSize)
: mNextHeapZone(nil)
, mZoneHandle(nil)
, mChunkCount(0)
, mHeapZone(nil)
#if DEBUG_HEAP_INTEGRITY
, mSignature(kHeapZoneSignature)
#endif
// This ctor is used for zones in our heap, which are allocated with
// NewPtr
//--------------------------------------------------------------------
{
public:
SetupHeapZone(zonePtr, ptrSize);
}
static const SInt32 kNumMasterPointerBlocks;
static const SInt32 kApplicationStackSizeIncrease;
static const SInt32 kHeapZoneHeapPercentage;
nsAllocatorManager();
~nsAllocatorManager();
static OSErr InitializeMacMemory(SInt32 inNumMasterPointerBlocks,
SInt32 inAppStackSizeInc);
nsMemAllocator* GetAllocatorForBlockSize(size_t blockSize);
static nsAllocatorManager* GetAllocatorManager();
protected:
static nsAllocatorManager *sAllocatorManager;
private:
SInt32 mNumFixedSizeAllocators;
SInt32 mNumSmallBlockAllocators;
UInt32 mMinSmallBlockSize; // blocks >= this size come out of the small block allocator
UInt32 mMinLargeBlockSize; // blocks >= this size come out of the large allocator
nsMemAllocator** mFixedSizeAllocators; // array of pointers to allocator objects
nsMemAllocator** mSmallBlockAllocators; // array of pointers to allocator objects
nsMemAllocator* mLargeAllocator;
THz mHeapZone; // the heap zone for our memory heaps
};
//--------------------------------------------------------------------
nsHeapZoneHeader::nsHeapZoneHeader(Handle zoneHandle, Size handleSize)
: mNextHeapZone(nil)
, mZoneHandle(zoneHandle)
, mChunkCount(0)
, mHeapZone(nil)
#if DEBUG_HEAP_INTEGRITY
, mSignature(kHeapZoneSignature)
#endif
// This ctor is used for zones in temporary memory, which are allocated
// with TempNewHandle
//--------------------------------------------------------------------
{
// handle should be locked here
SetupHeapZone(*zoneHandle, handleSize);
}
//--------------------------------------------------------------------
nsHeapZoneHeader::~nsHeapZoneHeader()
//--------------------------------------------------------------------
{
if (mZoneHandle)
::DisposeHandle(mZoneHandle);
else
::DisposePtr((Ptr)this);
MEM_ASSERT(::MemError() == noErr, "Error on Mac memory dispose");
}
//--------------------------------------------------------------------
void nsHeapZoneHeader::SetupHeapZone(Ptr zonePtr, Size ptrSize)
//--------------------------------------------------------------------
{
Ptr zoneStart = zonePtr + sizeof(nsHeapZoneHeader);
Ptr endZone = zonePtr + ptrSize;
::InitZone(nil, kHeapZoneMasterPointers, endZone, zoneStart);
mHeapZone = (THz)zoneStart;
// set the current zone back to the application zone, because InitZone changes it
::SetZone(::ApplicationZone());
}
//--------------------------------------------------------------------
Ptr nsHeapZoneHeader::AllocateZonePtr(Size ptrSize)
//--------------------------------------------------------------------
{
::SetZone(mHeapZone);
Ptr thePtr = ::NewPtr(ptrSize);
::SetZone(::ApplicationZone());
mChunkCount += (thePtr != nil);
return thePtr;
}
//--------------------------------------------------------------------
void nsHeapZoneHeader::DisposeZonePtr(Ptr thePtr, Boolean &outWasLastChunk)
//--------------------------------------------------------------------
{
MEM_ASSERT(::PtrZone(thePtr) == mHeapZone, "Ptr disposed from wrong zone!");
::DisposePtr(thePtr);
mChunkCount --;
outWasLastChunk = (mChunkCount == 0);
}
//--------------------------------------------------------------------
/* static */ nsHeapZoneHeader* nsHeapZoneHeader::GetZoneFromPtr(Ptr subheapPtr)
//--------------------------------------------------------------------
{
THz ptrZone = ::PtrZone(subheapPtr);
MEM_ASSERT(ptrZone && (::MemError() == noErr), "Problem getting zone from ptr");
return (nsHeapZoneHeader *)((char *)ptrZone - sizeof(nsHeapZoneHeader));
}
#pragma mark -
const SInt32 nsAllocatorManager::kNumMasterPointerBlocks = 30;
@ -103,10 +166,12 @@ const SInt32 nsAllocatorManager::kHeapZoneHeapPercentage = 60;
nsAllocatorManager* nsAllocatorManager::sAllocatorManager = nil;
//--------------------------------------------------------------------
nsAllocatorManager::nsAllocatorManager() :
mFixedSizeAllocators(nil),
mSmallBlockAllocators(nil),
mLargeAllocator(nil)
nsAllocatorManager::nsAllocatorManager()
: mFixedSizeAllocators(nil)
, mSmallBlockAllocators(nil)
, mLargeAllocator(nil)
, mFirstHeapZone(nil)
, mLastHeapZone(nil)
//--------------------------------------------------------------------
{
mMinSmallBlockSize = 44; // some magic numbers for now
@ -129,6 +194,7 @@ nsAllocatorManager::nsAllocatorManager() :
mFixedSizeAllocators[i] = (nsMemAllocator *)NewPtr(sizeof(nsFixedSizeAllocator));
if (mFixedSizeAllocators[i] == nil)
throw((OSErr)memFullErr);
new (mFixedSizeAllocators[i]) nsFixedSizeAllocator((i + 1) * 4);
}
for (SInt32 i = 0; i < mNumSmallBlockAllocators; i ++)
@ -136,11 +202,13 @@ nsAllocatorManager::nsAllocatorManager() :
mSmallBlockAllocators[i] = (nsMemAllocator *)NewPtr(sizeof(nsSmallHeapAllocator));
if (mSmallBlockAllocators[i] == nil)
throw((OSErr)memFullErr);
new (mSmallBlockAllocators[i]) nsSmallHeapAllocator();
}
mLargeAllocator = (nsMemAllocator *)NewPtr(sizeof(nsLargeHeapAllocator));
if (mLargeAllocator == nil)
throw((OSErr)memFullErr);
new (mLargeAllocator) nsLargeHeapAllocator();
// make the heap zone for our subheaps
UInt32 heapZoneSize;
@ -148,30 +216,10 @@ nsAllocatorManager::nsAllocatorManager() :
heapZoneSize = ( kHeapZoneHeapPercentage * ::FreeMem() ) / 100;
heapZoneSize = ( ( heapZoneSize + 3 ) & ~3 ); // round up to a multiple of 4 bytes
Ptr heapZone = ::NewPtr(heapZoneSize);
if (heapZone == nil)
nsHeapZoneHeader *firstZone = MakeNewHeapZone(heapZoneSize, heapZoneSize);
if (!firstZone)
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);
}
//--------------------------------------------------------------------
@ -215,6 +263,131 @@ nsMemAllocator* nsAllocatorManager::GetAllocatorForBlockSize(size_t blockSize)
return mLargeAllocator;
}
//--------------------------------------------------------------------
nsHeapZoneHeader* nsAllocatorManager::MakeNewHeapZone(Size zoneSize, Size minZoneSize)
//--------------------------------------------------------------------
{
if (mFirstHeapZone == nil)
{
Ptr firstZonePtr = ::NewPtr(zoneSize);
if (!firstZonePtr) return nil;
mFirstHeapZone = new (firstZonePtr) nsHeapZoneHeader(firstZonePtr, zoneSize);
mLastHeapZone = mFirstHeapZone;
}
else
{
OSErr err;
Handle tempMemHandle = ::TempNewHandle(zoneSize, &err);
while (!tempMemHandle && zoneSize > minZoneSize)
{
zoneSize -= (128 * 1024);
tempMemHandle = ::TempNewHandle(zoneSize, &err);
}
if (!tempMemHandle) return nil;
// first, lock the handle hi
HLockHi(tempMemHandle);
nsHeapZoneHeader *newZone = new (*tempMemHandle) nsHeapZoneHeader(tempMemHandle, zoneSize);
mLastHeapZone->SetNextZone(newZone);
mLastHeapZone = newZone;
}
return mLastHeapZone;
}
// 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::kTempMemHeapZoneSize = 1024 * 1024; // 1MB temp handles
const Size nsAllocatorManager::kTempMemHeapMinZoneSize = 256 * 1024; // min 256K handle
//--------------------------------------------------------------------
Ptr nsAllocatorManager::AllocateSubheap(Size preferredSize, Size &outActualSize)
//--------------------------------------------------------------------
{
nsHeapZoneHeader *thisHeapZone = mFirstHeapZone;
// 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
preferredSize += ((preferredSize / kChunkSizeMultiple) - 1) * kMacMemoryPtrOvehead;
outActualSize = preferredSize;
while (thisHeapZone)
{
Ptr subheapPtr = thisHeapZone->AllocateZonePtr(preferredSize);
if (subheapPtr)
return subheapPtr;
thisHeapZone = thisHeapZone->GetNextZone();
}
// we failed to allocate. Let's make a new heap zone
thisHeapZone = MakeNewHeapZone(kTempMemHeapZoneSize, kTempMemHeapMinZoneSize);
if (thisHeapZone)
return thisHeapZone->AllocateZonePtr(preferredSize);
return nil;
}
//--------------------------------------------------------------------
void nsAllocatorManager::FreeSubheap(Ptr subheapPtr)
//--------------------------------------------------------------------
{
nsHeapZoneHeader *ptrHeapZone = nsHeapZoneHeader::GetZoneFromPtr(subheapPtr);
#if DEBUG_HEAP_INTEGRITY
MEM_ASSERT(ptrHeapZone->IsGoodZone(), "Got bad heap zone header");
#endif
Boolean lastChunk;
ptrHeapZone->DisposeZonePtr(subheapPtr, lastChunk);
if (lastChunk)
{
// remove from the list
nsHeapZoneHeader *prevZone = nil;
nsHeapZoneHeader *nextZone = nil;
nsHeapZoneHeader *thisZone = mFirstHeapZone;
while (thisZone)
{
nextZone = thisZone->GetNextZone();
if (thisZone == ptrHeapZone)
break;
prevZone = thisZone;
thisZone = nextZone;
}
if (thisZone)
{
if (prevZone)
prevZone->SetNextZone(nextZone);
if (mFirstHeapZone == thisZone)
mFirstHeapZone = nextZone;
if (mLastHeapZone == thisZone)
mLastHeapZone = prevZone;
}
// dispose it
ptrHeapZone->~nsHeapZoneHeader(); // this disposes the ptr/handle
}
}
//--------------------------------------------------------------------
/* static */ OSErr nsAllocatorManager::InitializeMacMemory(SInt32 inNumMasterPointerBlocks,
@ -258,7 +431,7 @@ nsMemAllocator* nsAllocatorManager::GetAllocatorForBlockSize(size_t blockSize)
//--------------------------------------------------------------------
/* static */ nsAllocatorManager * nsAllocatorManager::GetAllocatorManager()
/* static */ nsAllocatorManager * nsAllocatorManager::CreateAllocatorManager()
//--------------------------------------------------------------------
{
if (sAllocatorManager) return sAllocatorManager;
@ -269,6 +442,57 @@ nsMemAllocator* nsAllocatorManager::GetAllocatorForBlockSize(size_t blockSize)
return sAllocatorManager;
}
#if STATS_MAC_MEMORY
//--------------------------------------------------------------------
void nsAllocatorManager::DumpMemoryStats()
//--------------------------------------------------------------------
{
UInt32 i;
char outString[ 1024 ];
PRFileDesc *outFile;
// Enter a valid, UNIX-style full path on your system to get this
// to work.
outFile = PR_Open("/System/MemoryStats.txt", PR_RDWR | PR_CREATE_FILE | PR_TRUNCATE, 0644);
if ( outFile == NULL )
{
return;
}
for (i = 0; i < mNumFixedSizeAllocators; i ++)
{
mFixedSizeAllocators[i]->DumpMemoryStats(outFile);
}
for (i = 0; i < mNumSmallBlockAllocators; i ++)
{
mSmallBlockAllocators[i]->DumpMemoryStats(outFile);
}
mLargeAllocator->DumpMemoryStats(outFile);
PR_Close(outFile);
}
//--------------------------------------------------------------------
void WriteString(PRFileDesc *file, const char * string)
//--------------------------------------------------------------------
{
long len;
long bytesWritten;
len = strlen ( string );
if ( len >= 1024 ) Debugger();
bytesWritten = PR_Write(file, string, len);
}
#endif
#pragma mark -
@ -348,13 +572,11 @@ void *calloc(size_t nele, size_t elesize)
#pragma mark -
#if 0
/*----------------------------------------------------------------------------
__MemInitialize
Note the people can call malloc() or new() before we come here,
so we only initialize the memory if we've not alredy done it.s
so we can't rely on this being called before we do allocation.
----------------------------------------------------------------------------*/
pascal OSErr __MemInitialize(const CFragInitBlock *theInitBlock)
@ -389,9 +611,11 @@ pascal void __MemTerminate(void)
ProfilerTerm();
#endif
#if STATS_MAC_MEMORY
nsAllocatorManager::GetAllocatorManager()->DumpMemoryStats();
#endif
__terminate();
}
#endif

View File

@ -18,7 +18,9 @@
#include <MacTypes.h>
#if STATS_MAC_MEMORY
#include "prio.h"
#endif
#ifdef __cplusplus
extern "C" {
@ -30,6 +32,123 @@ void* realloc(void* block, size_t newSize);
void *calloc(size_t nele, size_t elesize);
#if STATS_MAC_MEMORY
void WriteString(PRFileDesc *file, const char * string);
#endif
#ifdef __cplusplus
}
#endif
//--------------------------------------------------------------------
class nsHeapZoneHeader
{
public:
nsHeapZoneHeader(Ptr zonePtr, Size ptrSize);
nsHeapZoneHeader(Handle zoneHandle, Size handleSize);
~nsHeapZoneHeader();
nsHeapZoneHeader * GetNextZone() { return mNextHeapZone; }
void SetNextZone(nsHeapZoneHeader *nextZone) { mNextHeapZone = nextZone; }
Ptr AllocateZonePtr(Size ptrSize);
void DisposeZonePtr(Ptr thePtr, Boolean &outWasLastChunk);
#if DEBUG_HEAP_INTEGRITY
Boolean IsGoodZone() { return (mSignature == kHeapZoneSignature); }
#endif
static nsHeapZoneHeader* GetZoneFromPtr(Ptr subheapPtr);
protected:
void SetupHeapZone(Ptr zonePtr, Size zoneSize);
enum
{
kHeapZoneMasterPointers = 24 // this number doesn't really matter, because we never
// allocate handles in our heap zones
};
#if DEBUG_HEAP_INTEGRITY
enum {
kHeapZoneSignature = 'HZne'
};
OSType mSignature;
#endif
nsHeapZoneHeader *mNextHeapZone;
Handle mZoneHandle; // the handle containing the zone. Nil if Ptr in app heap
UInt32 mChunkCount; // how many chunks are allocated in this zone
THz mHeapZone;
};
class nsAllocatorManager
{
public:
static const SInt32 kNumMasterPointerBlocks;
static const SInt32 kApplicationStackSizeIncrease;
static const SInt32 kHeapZoneHeapPercentage;
static const SInt32 kTempMemHeapZoneSize;
static const SInt32 kTempMemHeapMinZoneSize;
static const Size kChunkSizeMultiple;
static nsAllocatorManager* GetAllocatorManager() { return sAllocatorManager ? sAllocatorManager : CreateAllocatorManager(); }
nsAllocatorManager();
~nsAllocatorManager();
static OSErr InitializeMacMemory(SInt32 inNumMasterPointerBlocks,
SInt32 inAppStackSizeInc);
nsMemAllocator* GetAllocatorForBlockSize(size_t blockSize);
Ptr AllocateSubheap(Size preferredSize, Size &outActualSize);
void FreeSubheap(Ptr subheapPtr);
#if STATS_MAC_MEMORY
void DumpMemoryStats();
#endif
protected:
static nsAllocatorManager * CreateAllocatorManager();
static const Size kMacMemoryPtrOvehead;
nsHeapZoneHeader * MakeNewHeapZone(Size zoneSize, Size minZoneSize);
private:
SInt32 mNumFixedSizeAllocators;
SInt32 mNumSmallBlockAllocators;
UInt32 mMinSmallBlockSize; // blocks >= this size come out of the small block allocator
UInt32 mMinLargeBlockSize; // blocks >= this size come out of the large allocator
nsMemAllocator** mFixedSizeAllocators; // array of pointers to allocator objects
nsMemAllocator** mSmallBlockAllocators; // array of pointers to allocator objects
nsMemAllocator* mLargeAllocator;
nsHeapZoneHeader* mFirstHeapZone; // first of a linked list of heap zones
nsHeapZoneHeader* mLastHeapZone; // last of a linked list of heap zones
THz mHeapZone; // the heap zone for our memory heaps
static nsAllocatorManager *sAllocatorManager;
};

View File

@ -20,17 +20,19 @@
#include <MacMemory.h>
#include "nsMemAllocator.h"
#include "nsAllocatorManager.h"
#include "nsFixedSizeAllocator.h"
const UInt32 FixedMemoryBlock::kFixedSizeBlockOverhead = sizeof(FixedMemoryBlockHeader) + MEMORY_BLOCK_TAILER_SIZE;
//--------------------------------------------------------------------
nsFixedSizeAllocator::nsFixedSizeAllocator(THz heapZone, size_t blockSize)
: nsMemAllocator(heapZone)
nsFixedSizeAllocator::nsFixedSizeAllocator(size_t blockSize)
: nsMemAllocator()
, mBlockSize(blockSize)
, mChunkWithSpace(nil)
//--------------------------------------------------------------------
{
mBaseChunkSize = mTempChunkSize = (nsMemAllocator::kChunkSizeMultiple);
mBaseChunkSize = mTempChunkSize = (nsAllocatorManager::kChunkSizeMultiple);
}
//--------------------------------------------------------------------
@ -46,6 +48,9 @@ nsHeapChunk* nsFixedSizeAllocator::FindChunkWithSpace(size_t blockSize) const
{
nsFixedSizeHeapChunk* chunk = (nsFixedSizeHeapChunk *)mFirstChunk;
if (mChunkWithSpace && mChunkWithSpace->GetFreeList())
return mChunkWithSpace;
// Try to find an existing chunk with a free block.
while (chunk != nil)
{
@ -69,10 +74,12 @@ void *nsFixedSizeAllocator::AllocatorMakeBlock(size_t blockSize)
{
chunk = (nsFixedSizeHeapChunk *)AllocateChunk(blockSize);
if (!chunk) return nil;
mChunkWithSpace = chunk;
}
FixedMemoryBlock* blockHeader = chunk->FetchFirstFree();
#if DEBUG_HEAP_INTEGRITY
blockHeader->SetHeaderTag(kUsedBlockHeaderTag);
blockHeader->SetTrailerTag(GetAllocatorBlockSize(), kUsedBlockTrailerTag);
@ -119,8 +126,14 @@ void nsFixedSizeAllocator::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
}
}
@ -170,13 +183,13 @@ nsHeapChunk *nsFixedSizeAllocator::AllocateChunk(size_t requestedBlockSize)
//--------------------------------------------------------------------
{
Size actualChunkSize;
Handle tempMemHandle;
Ptr chunkMemory = DoMacMemoryAllocation(mBaseChunkSize, actualChunkSize, &tempMemHandle);
Ptr chunkMemory = nsAllocatorManager::GetAllocatorManager()->AllocateSubheap(mBaseChunkSize, actualChunkSize);
// use placement new to initialize the chunk in the memory block
nsHeapChunk *newHeapChunk = new (chunkMemory) nsFixedSizeHeapChunk(this, actualChunkSize, tempMemHandle);
nsHeapChunk *newHeapChunk = new (chunkMemory) nsFixedSizeHeapChunk(this, actualChunkSize);
if (newHeapChunk)
AddToChunkList(newHeapChunk);
return newHeapChunk;
}
@ -190,11 +203,7 @@ void nsFixedSizeAllocator::FreeChunk(nsHeapChunk *chunkToFree)
nsFixedSizeHeapChunk *thisChunk = (nsFixedSizeHeapChunk *)chunkToFree;
thisChunk->~nsFixedSizeHeapChunk();
Handle tempMemHandle = thisChunk->GetMemHandle();
if (tempMemHandle)
DisposeHandle(tempMemHandle);
else
DisposePtr((Ptr)thisChunk);
nsAllocatorManager::GetAllocatorManager()->FreeSubheap((Ptr)thisChunk);
}
@ -203,9 +212,8 @@ void nsFixedSizeAllocator::FreeChunk(nsHeapChunk *chunkToFree)
//--------------------------------------------------------------------
nsFixedSizeHeapChunk::nsFixedSizeHeapChunk(
nsMemAllocator *inOwningAllocator,
Size heapSize,
Handle tempMemHandle) :
nsHeapChunk(inOwningAllocator, heapSize, tempMemHandle)
Size heapSize) :
nsHeapChunk(inOwningAllocator, heapSize)
//--------------------------------------------------------------------
{
nsFixedSizeAllocator *allocator = (nsFixedSizeAllocator *)mOwningAllocator;

View File

@ -106,7 +106,7 @@ class nsFixedSizeAllocator : public nsMemAllocator
public:
nsFixedSizeAllocator(THz heapZone, size_t blockSize);
nsFixedSizeAllocator(size_t blockSize);
~nsFixedSizeAllocator();
virtual void * AllocatorMakeBlock(size_t blockSize);
@ -130,7 +130,9 @@ class nsFixedSizeAllocator : public nsMemAllocator
UInt32 mBlockSize; // upper bound for blocks allocated in this heap
// does not include block overhead
nsFixedSizeHeapChunk *mChunkWithSpace; // cheap optimization
#if STATS_MAC_MEMORY
UInt32 mChunksAllocated;
UInt32 mMaxChunksAllocated;
@ -156,20 +158,20 @@ class nsFixedSizeHeapChunk : public nsHeapChunk
{
public:
nsFixedSizeHeapChunk(nsMemAllocator *inOwningAllocator, Size heapSize, Handle tempMemHandle);
~nsFixedSizeHeapChunk();
nsFixedSizeHeapChunk(nsMemAllocator *inOwningAllocator, Size heapSize);
~nsFixedSizeHeapChunk();
FixedMemoryBlock* GetFreeList() const { return mFreeList; }
void SetFreeList(FixedMemoryBlock *nextFree) { mFreeList = nextFree; }
void SetFreeList(FixedMemoryBlock *nextFree) { mFreeList = nextFree; }
FixedMemoryBlock* FetchFirstFree();
void ReturnToFreeList(FixedMemoryBlock *freeBlock);
void ReturnToFreeList(FixedMemoryBlock *freeBlock);
protected:
#if STATS_MAC_MEMORY
UInt32 chunkSize;
UInt32 numBlocks;
UInt32 chunkSize;
UInt32 numBlocks;
#endif
FixedMemoryBlock *mFreeList;

View File

@ -19,14 +19,15 @@
#include <MacMemory.h>
#include "nsMemAllocator.h"
#include "nsAllocatorManager.h"
#include "nsLargeHeapAllocator.h"
const UInt32 LargeBlockHeader::kLargeBlockOverhead = sizeof(LargeBlockHeader) + MEMORY_BLOCK_TAILER_SIZE;
//--------------------------------------------------------------------
nsLargeHeapAllocator::nsLargeHeapAllocator(THz heapZone)
: nsMemAllocator(heapZone)
nsLargeHeapAllocator::nsLargeHeapAllocator()
: nsMemAllocator()
//--------------------------------------------------------------------
{
mBaseChunkSize = mTempChunkSize = (64 * 1024);
@ -160,17 +161,16 @@ nsHeapChunk *nsLargeHeapAllocator::AllocateChunk(size_t requestedBlockSize)
//--------------------------------------------------------------------
{
Size chunkSize = mBaseChunkSize, actualChunkSize;
Handle tempMemHandle;
size_t paddedBlockSize = (( requestedBlockSize + 3 ) & ~3) + 3 * LargeBlockHeader::kLargeBlockOverhead + sizeof(nsLargeHeapChunk);
if (paddedBlockSize > chunkSize)
chunkSize = paddedBlockSize;
Ptr chunkMemory = DoMacMemoryAllocation(chunkSize, actualChunkSize, &tempMemHandle);
Ptr chunkMemory = nsAllocatorManager::GetAllocatorManager()->AllocateSubheap(chunkSize, actualChunkSize);
// use placement new to initialize the chunk in the memory block
nsHeapChunk *newHeapChunk = new (chunkMemory) nsLargeHeapChunk(this, actualChunkSize, tempMemHandle);
nsHeapChunk *newHeapChunk = new (chunkMemory) nsLargeHeapChunk(this, actualChunkSize);
if (newHeapChunk)
AddToChunkList(newHeapChunk);
@ -188,11 +188,7 @@ void nsLargeHeapAllocator::FreeChunk(nsHeapChunk *chunkToFree)
nsLargeHeapChunk *thisChunk = (nsLargeHeapChunk *)chunkToFree;
thisChunk->~nsLargeHeapChunk();
Handle tempMemHandle = thisChunk->GetMemHandle();
if (tempMemHandle)
DisposeHandle(tempMemHandle);
else
DisposePtr((Ptr)thisChunk);
nsAllocatorManager::GetAllocatorManager()->FreeSubheap((Ptr)thisChunk);
}
@ -201,9 +197,8 @@ void nsLargeHeapAllocator::FreeChunk(nsHeapChunk *chunkToFree)
//--------------------------------------------------------------------
nsLargeHeapChunk::nsLargeHeapChunk(
nsMemAllocator *inOwningAllocator,
Size heapSize,
Handle tempMemHandle) :
nsHeapChunk(inOwningAllocator, heapSize, tempMemHandle)
Size heapSize) :
nsHeapChunk(inOwningAllocator, heapSize)
//--------------------------------------------------------------------
{
heapSize -= sizeof(nsLargeHeapChunk); // subtract heap overhead

View File

@ -108,7 +108,7 @@ class nsLargeHeapAllocator : public nsMemAllocator
public:
nsLargeHeapAllocator(THz heapZone);
nsLargeHeapAllocator();
~nsLargeHeapAllocator();
@ -136,8 +136,7 @@ class nsLargeHeapChunk : public nsHeapChunk
public:
nsLargeHeapChunk( nsMemAllocator *inOwningAllocator,
Size heapSize,
Handle tempMemHandle);
Size heapSize);
~nsLargeHeapChunk();
LargeBlockHeader* GetHeadBlock() { return mHead; }

View File

@ -15,18 +15,19 @@
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
* Reserved. */
#include <stdio.h>
#include <MacMemory.h>
#include "nsMemAllocator.h"
#include "nsAllocatorManager.h"
//--------------------------------------------------------------------
nsHeapChunk::nsHeapChunk(nsMemAllocator *inOwningAllocator, Size heapSize, Handle tempMemHandle)
nsHeapChunk::nsHeapChunk(nsMemAllocator *inOwningAllocator, Size heapSize)
: mOwningAllocator(inOwningAllocator)
, mNextChunk(nil)
, mHeapSize(heapSize)
, mUsedBlocks(0)
, mTempMemHandle(tempMemHandle)
#if DEBUG_HEAP_INTEGRITY
, mSignature(kChunkSignature)
#endif
@ -46,13 +47,22 @@ nsHeapChunk::~nsHeapChunk()
#pragma mark -
//--------------------------------------------------------------------
nsMemAllocator::nsMemAllocator(THz inHeapZone)
: mHeapZone(inHeapZone)
, mFirstChunk(nil)
nsMemAllocator::nsMemAllocator()
: mFirstChunk(nil)
, mLastChunk(nil)
#if DEBUG_HEAP_INTEGRITY
, mSignature(kMemAllocatorSignature)
#endif
#if STATS_MAC_MEMORY
, mCurBlockCount(0)
, mMaxBlockCount(0)
, mCurBlockSpaceUsed(0)
, mMaxBlockSpaceUsed(0)
, mCurHeapSpaceUsed(0)
, mMaxHeapSpaceUsed(0)
, mCurSubheapCount(0)
, mMaxSubheapCount(0)
#endif
//--------------------------------------------------------------------
{
}
@ -109,6 +119,10 @@ void nsMemAllocator::AddToChunkList(nsHeapChunk *inNewChunk)
mCurSubheapCount ++;
if (mCurSubheapCount > mMaxSubheapCount)
mMaxSubheapCount = mCurSubheapCount;
mCurHeapSpaceUsed += inNewChunk->GetChunkSize();
if (mCurHeapSpaceUsed > mMaxHeapSpaceUsed)
mMaxHeapSpaceUsed = mCurHeapSpaceUsed;
#endif
}
@ -146,67 +160,13 @@ void nsMemAllocator::RemoveFromChunkList(nsHeapChunk *inChunk)
#if STATS_MAC_MEMORY
mCurSubheapCount --;
mCurHeapSpaceUsed -= inChunk->GetChunkSize();
#endif
}
// amount of free space to maintain in the heap. This is used by
// plugins, GWorlds and other things.
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,
Handle *outTempMemHandle)
// This is the routine that does the actual memory allocation.
// Possible results:
// 1. Allocate pointer in heap. Return ptr, *outTempMemHandle==nil.
// 2. Allocate handle in temp mem. Return *handle, and put handle in *outTempMemHandle
// 3. Fail to allocate. Return nil, *outTempMemHandle==nil.
//
// outActualSize may be larger than preferredSize because we
// want to avoid heap fragmentation by keeping all blocks multiples
// of one smallest block size. outActualSize will not be smaller
// than preferredSize
//--------------------------------------------------------------------
{
*outTempMemHandle = nil;
// 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
preferredSize += ((preferredSize / kChunkSizeMultiple) - 1) * kMacMemoryPtrOvehead;
outActualSize = preferredSize;
// 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;
// that failed, so try temp mem now
OSErr err;
Handle tempMemHandle = ::TempNewHandle(preferredSize, &err);
if (tempMemHandle != nil)
{
HLock(tempMemHandle); // may thee remain locked for all time
*outTempMemHandle = tempMemHandle;
return *tempMemHandle;
}
return nil; // failure
}
#pragma mark -
#if STATS_MAC_MEMORY
@ -246,4 +206,31 @@ void nsMemAllocator::AccountForFreedBlock(size_t logicalSize)
mCurBlockSpaceUsed -= logicalSize;
}
//--------------------------------------------------------------------
void nsMemAllocator::DumpMemoryStats(PRFileDesc *outFile)
//--------------------------------------------------------------------
{
char outString[ 1024 ];
WriteString ( outFile, "\n\n--------------------------------------------------------------------------------\n" );
WriteString(outFile, "Stats for heap\n");
WriteString ( outFile, "--------------------------------------------------------------------------------\n" );
WriteString ( outFile, " Current Max\n" );
WriteString ( outFile, " ---------- -------\n" );
sprintf( outString, "Num chunks: %10d %10d\n", mCurSubheapCount, mMaxSubheapCount);
WriteString ( outFile, outString );
sprintf( outString, "Chunk total: %10d %10d\n", mCurHeapSpaceUsed, mMaxHeapSpaceUsed);
WriteString ( outFile, outString );
sprintf( outString, "Block space: %10d %10d\n", mCurBlockSpaceUsed, mMaxBlockSpaceUsed );
WriteString ( outFile, outString );
sprintf( outString, "Blocks used: %10d %10d\n", mCurBlockCount, mMaxBlockCount );
WriteString ( outFile, outString );
WriteString ( outFile, " -------\n" );
sprintf( outString, "%s of allocated space used: %10.2f\n", "%", 100.0 * mMaxBlockSpaceUsed / mMaxHeapSpaceUsed );
WriteString ( outFile, outString );
WriteString ( outFile, "\n\n");
}
#endif

View File

@ -18,6 +18,10 @@
#include <stddef.h>
#if STATS_MAC_MEMORY
#include "prio.h"
#endif
class nsMemAllocator;
class nsHeapChunk;
@ -86,7 +90,7 @@ class nsHeapChunk
{
public:
nsHeapChunk(nsMemAllocator *inOwningAllocator, Size heapSize, Handle tempMemHandle);
nsHeapChunk(nsMemAllocator *inOwningAllocator, Size heapSize);
~nsHeapChunk();
nsHeapChunk* GetNextChunk() const { return mNextChunk; }
@ -99,8 +103,8 @@ class nsHeapChunk
Boolean IsEmpty() const { return mUsedBlocks == 0; }
Handle GetMemHandle() { return mTempMemHandle; }
UInt32 GetChunkSize() { return mHeapSize; }
#if DEBUG_HEAP_INTEGRITY
Boolean IsGoodChunk() { return mSignature == kChunkSignature; }
#endif
@ -117,9 +121,6 @@ class nsHeapChunk
nsHeapChunk *mNextChunk;
UInt32 mUsedBlocks;
UInt32 mHeapSize;
private:
Handle mTempMemHandle; // if nil, this chunk is a pointer in the heap
};
@ -130,7 +131,7 @@ class nsMemAllocator
{
public:
nsMemAllocator(THz inHeapZone);
nsMemAllocator();
virtual ~nsMemAllocator() = 0;
static size_t GetBlockSize(void *thisBlock);
@ -155,13 +156,7 @@ class nsMemAllocator
#endif
protected:
static const Size kFreeHeapSpace;
static const Size kChunkSizeMultiple;
static const Size kMacMemoryPtrOvehead;
Ptr DoMacMemoryAllocation(Size preferredSize, Size &outActualSize, Handle *outTempMemHandle);
void AddToChunkList(nsHeapChunk *inNewChunk);
void RemoveFromChunkList(nsHeapChunk *inChunk);
@ -178,8 +173,6 @@ class nsMemAllocator
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
@ -189,6 +182,8 @@ class nsMemAllocator
void AccountForFreedBlock(size_t logicalSize);
void AccountForResizedBlock(size_t oldLogicalSize, size_t newLogicalSize);
void DumpMemoryStats(PRFileDesc *statsFile);
private:
UInt32 mCurBlockCount; // number of malloc blocks allocated now

View File

@ -20,17 +20,18 @@
#include <MacMemory.h>
#include "nsMemAllocator.h"
#include "nsAllocatorManager.h"
#include "nsSmallHeapAllocator.h"
const UInt32 SmallHeapBlock::kBlockOverhead = sizeof(SmallHeapBlock) + MEMORY_BLOCK_TAILER_SIZE;
//--------------------------------------------------------------------
nsSmallHeapAllocator::nsSmallHeapAllocator(THz heapZone)
: nsMemAllocator(heapZone)
nsSmallHeapAllocator::nsSmallHeapAllocator()
: nsMemAllocator()
//--------------------------------------------------------------------
{
mBaseChunkSize = mTempChunkSize = (nsMemAllocator::kChunkSizeMultiple);
mBaseChunkSize = mTempChunkSize = (nsAllocatorManager::kChunkSizeMultiple);
}
//--------------------------------------------------------------------
@ -146,12 +147,10 @@ nsHeapChunk *nsSmallHeapAllocator::AllocateChunk(size_t blockSize)
minChunkSize = mBaseChunkSize;
Size actualChunkSize;
Handle tempMemHandle;
Ptr chunkMemory = DoMacMemoryAllocation(minChunkSize, actualChunkSize, &tempMemHandle);
Ptr chunkMemory = nsAllocatorManager::GetAllocatorManager()->AllocateSubheap(mBaseChunkSize, actualChunkSize);
// use placement new to initialize the chunk in the memory block
nsHeapChunk *newHeapChunk = new (chunkMemory) nsSmallHeapChunk(this, actualChunkSize, tempMemHandle);
nsHeapChunk *newHeapChunk = new (chunkMemory) nsSmallHeapChunk(this, actualChunkSize);
if (newHeapChunk)
AddToChunkList(newHeapChunk);
@ -168,11 +167,7 @@ void nsSmallHeapAllocator::FreeChunk(nsHeapChunk *chunkToFree)
nsSmallHeapChunk *thisChunk = (nsSmallHeapChunk *)chunkToFree;
thisChunk->~nsSmallHeapChunk();
Handle tempMemHandle = thisChunk->GetMemHandle();
if (tempMemHandle)
DisposeHandle(tempMemHandle);
else
DisposePtr((Ptr)thisChunk);
nsAllocatorManager::GetAllocatorManager()->FreeSubheap((Ptr)thisChunk);
}
@ -181,9 +176,8 @@ void nsSmallHeapAllocator::FreeChunk(nsHeapChunk *chunkToFree)
//--------------------------------------------------------------------
nsSmallHeapChunk::nsSmallHeapChunk(
nsMemAllocator *inOwningAllocator,
Size heapSize,
Handle tempMemHandle) :
nsHeapChunk(inOwningAllocator, heapSize, tempMemHandle),
Size heapSize) :
nsHeapChunk(inOwningAllocator, heapSize),
mOverflow(nil)
//--------------------------------------------------------------------
{
@ -298,8 +292,6 @@ void *nsSmallHeapChunk::GetSpaceForBlock(size_t blockSize)
// room for another allocation out of the
// block, then split the block up.
//blockToCarve->SetUnusedBlockSize(roundedBlockSize);
//leftovers = blockToCarveSize - blockToCarve->GetBlockHeapUsage();
SInt32 leftovers = blockToCarveSize - roundedBlockSize - SmallHeapBlock::kBlockOverhead;
if (leftovers >= kDefaultSmallHeadMinSize)

View File

@ -130,7 +130,7 @@ class nsSmallHeapAllocator : public nsMemAllocator
public:
nsSmallHeapAllocator(THz heapZone);
nsSmallHeapAllocator();
~nsSmallHeapAllocator();
virtual void * AllocatorMakeBlock(size_t blockSize);
@ -153,9 +153,7 @@ class nsSmallHeapChunk : public nsHeapChunk
{
public:
nsSmallHeapChunk( nsMemAllocator *inOwningAllocator,
Size heapSize,
Handle tempMemHandle);
nsSmallHeapChunk(nsMemAllocator *inOwningAllocator, Size heapSize);
~nsSmallHeapChunk();
void * GetSpaceForBlock(UInt32 roundedBlockSize);