Alter AllocSet routines so that requests larger than
ALLOC_BIGCHUNK_LIMIT are always allocated as separate malloc() blocks, and are free()d immediately upon pfree(). Also, if such a chunk is enlarged with repalloc(), translate the operation into a realloc() so as to minimize memory usage. Of course, these large chunks still get freed automatically if the alloc set is reset. I have set ALLOC_BIGCHUNK_LIMIT at 64K for now, but perhaps another size would be better?
This commit is contained in:
parent
1b81fd7793
commit
2b67dc5387
@ -7,18 +7,26 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $Header: /cvsroot/pgsql/src/backend/utils/mmgr/aset.c,v 1.20 1999/07/17 20:18:13 momjian Exp $
|
* $Header: /cvsroot/pgsql/src/backend/utils/mmgr/aset.c,v 1.21 1999/08/24 20:11:17 tgl Exp $
|
||||||
*
|
*
|
||||||
* NOTE:
|
* NOTE:
|
||||||
* This is a new (Feb. 05, 1999) implementation of the allocation set
|
* This is a new (Feb. 05, 1999) implementation of the allocation set
|
||||||
* routines. AllocSet...() does not use OrderedSet...() any more.
|
* routines. AllocSet...() does not use OrderedSet...() any more.
|
||||||
* Instead it manages allocations in a block pool by itself, combining
|
* Instead it manages allocations in a block pool by itself, combining
|
||||||
* many small allocations in a few bigger blocks. AllocSetFree() does
|
* many small allocations in a few bigger blocks. AllocSetFree() normally
|
||||||
* never free() memory really. It just add's the free'd area to some
|
* doesn't free() memory really. It just add's the free'd area to some
|
||||||
* list for later reuse by AllocSetAlloc(). All memory blocks are free()'d
|
* list for later reuse by AllocSetAlloc(). All memory blocks are free()'d
|
||||||
* at once on AllocSetReset(), which happens when the memory context gets
|
* at once on AllocSetReset(), which happens when the memory context gets
|
||||||
* destroyed.
|
* destroyed.
|
||||||
* Jan Wieck
|
* Jan Wieck
|
||||||
|
*
|
||||||
|
* Performance improvement from Tom Lane, 8/99: for extremely large request
|
||||||
|
* sizes, we do want to be able to give the memory back to free() as soon
|
||||||
|
* as it is pfree()'d. Otherwise we risk tying up a lot of memory in
|
||||||
|
* freelist entries that might never be usable. This is specially needed
|
||||||
|
* when the caller is repeatedly repalloc()'ing a block bigger and bigger;
|
||||||
|
* the previous instances of the block were guaranteed to be wasted until
|
||||||
|
* AllocSetReset() under the old way.
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
#include "postgres.h"
|
#include "postgres.h"
|
||||||
@ -34,7 +42,9 @@
|
|||||||
/*--------------------
|
/*--------------------
|
||||||
* Chunk freelist k holds chunks of size 1 << (k + ALLOC_MINBITS),
|
* Chunk freelist k holds chunks of size 1 << (k + ALLOC_MINBITS),
|
||||||
* for k = 0 .. ALLOCSET_NUM_FREELISTS-2.
|
* for k = 0 .. ALLOCSET_NUM_FREELISTS-2.
|
||||||
* The last freelist holds all larger chunks.
|
* The last freelist holds all larger free chunks. Those chunks come in
|
||||||
|
* varying sizes depending on the request size, whereas smaller chunks are
|
||||||
|
* coerced to powers of 2 to improve their "recyclability".
|
||||||
*
|
*
|
||||||
* CAUTION: ALLOC_MINBITS must be large enough so that
|
* CAUTION: ALLOC_MINBITS must be large enough so that
|
||||||
* 1<<ALLOC_MINBITS is at least MAXALIGN,
|
* 1<<ALLOC_MINBITS is at least MAXALIGN,
|
||||||
@ -51,16 +61,28 @@
|
|||||||
* The first block allocated for an allocset has size ALLOC_MIN_BLOCK_SIZE.
|
* The first block allocated for an allocset has size ALLOC_MIN_BLOCK_SIZE.
|
||||||
* Each time we have to allocate another block, we double the block size
|
* Each time we have to allocate another block, we double the block size
|
||||||
* (if possible, and without exceeding ALLOC_MAX_BLOCK_SIZE), so as to reduce
|
* (if possible, and without exceeding ALLOC_MAX_BLOCK_SIZE), so as to reduce
|
||||||
* the load on "malloc".
|
* the bookkeeping load on malloc().
|
||||||
*
|
*
|
||||||
* Blocks allocated to hold oversize chunks do not follow this rule, however;
|
* Blocks allocated to hold oversize chunks do not follow this rule, however;
|
||||||
* they are just however big they need to be.
|
* they are just however big they need to be to hold that single chunk.
|
||||||
|
* AllocSetAlloc has some freedom about whether to consider a chunk larger
|
||||||
|
* than ALLOC_SMALLCHUNK_LIMIT to be "oversize". We require all chunks
|
||||||
|
* >= ALLOC_BIGCHUNK_LIMIT to be allocated as single-chunk blocks; those
|
||||||
|
* chunks are treated specially by AllocSetFree and AllocSetRealloc. For
|
||||||
|
* request sizes between ALLOC_SMALLCHUNK_LIMIT and ALLOC_BIGCHUNK_LIMIT,
|
||||||
|
* AllocSetAlloc has discretion whether to put the request into an existing
|
||||||
|
* block or make a single-chunk block.
|
||||||
|
*
|
||||||
|
* We must have ALLOC_MIN_BLOCK_SIZE > ALLOC_SMALLCHUNK_LIMIT and
|
||||||
|
* ALLOC_BIGCHUNK_LIMIT > ALLOC_SMALLCHUNK_LIMIT.
|
||||||
*--------------------
|
*--------------------
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#define ALLOC_MIN_BLOCK_SIZE 8192
|
#define ALLOC_MIN_BLOCK_SIZE (8 * 1024)
|
||||||
#define ALLOC_MAX_BLOCK_SIZE (8 * 1024 * 1024)
|
#define ALLOC_MAX_BLOCK_SIZE (8 * 1024 * 1024)
|
||||||
|
|
||||||
|
#define ALLOC_BIGCHUNK_LIMIT (64 * 1024)
|
||||||
|
/* Chunks >= ALLOC_BIGCHUNK_LIMIT are immediately free()d by pfree() */
|
||||||
|
|
||||||
#define ALLOC_BLOCKHDRSZ MAXALIGN(sizeof(AllocBlockData))
|
#define ALLOC_BLOCKHDRSZ MAXALIGN(sizeof(AllocBlockData))
|
||||||
#define ALLOC_CHUNKHDRSZ MAXALIGN(sizeof(AllocChunkData))
|
#define ALLOC_CHUNKHDRSZ MAXALIGN(sizeof(AllocChunkData))
|
||||||
@ -104,13 +126,6 @@ AllocSetFreeIndex(Size size)
|
|||||||
* Public routines
|
* Public routines
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/*
|
|
||||||
* AllocPointerIsValid(pointer)
|
|
||||||
* AllocSetIsValid(set)
|
|
||||||
*
|
|
||||||
* .. are now macros in aset.h -cim 4/27/91
|
|
||||||
*/
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* AllocSetInit
|
* AllocSetInit
|
||||||
* Initializes given allocation set.
|
* Initializes given allocation set.
|
||||||
@ -141,7 +156,7 @@ AllocSetInit(AllocSet set, AllocMode mode, Size limit)
|
|||||||
|
|
||||||
/*
|
/*
|
||||||
* AllocSetReset
|
* AllocSetReset
|
||||||
* Frees memory which is allocated in the given set.
|
* Frees all memory which is allocated in the given set.
|
||||||
*
|
*
|
||||||
* Exceptions:
|
* Exceptions:
|
||||||
* BadArg if set is invalid.
|
* BadArg if set is invalid.
|
||||||
@ -195,7 +210,7 @@ AllocSetAlloc(AllocSet set, Size size)
|
|||||||
{
|
{
|
||||||
AllocBlock block;
|
AllocBlock block;
|
||||||
AllocChunk chunk;
|
AllocChunk chunk;
|
||||||
AllocChunk freeref = NULL;
|
AllocChunk priorfree = NULL;
|
||||||
int fidx;
|
int fidx;
|
||||||
Size chunk_size;
|
Size chunk_size;
|
||||||
Size blksize;
|
Size blksize;
|
||||||
@ -212,7 +227,7 @@ AllocSetAlloc(AllocSet set, Size size)
|
|||||||
{
|
{
|
||||||
if (chunk->size >= size)
|
if (chunk->size >= size)
|
||||||
break;
|
break;
|
||||||
freeref = chunk;
|
priorfree = chunk;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -222,10 +237,10 @@ AllocSetAlloc(AllocSet set, Size size)
|
|||||||
*/
|
*/
|
||||||
if (chunk != NULL)
|
if (chunk != NULL)
|
||||||
{
|
{
|
||||||
if (freeref == NULL)
|
if (priorfree == NULL)
|
||||||
set->freelist[fidx] = (AllocChunk) chunk->aset;
|
set->freelist[fidx] = (AllocChunk) chunk->aset;
|
||||||
else
|
else
|
||||||
freeref->aset = chunk->aset;
|
priorfree->aset = chunk->aset;
|
||||||
|
|
||||||
chunk->aset = (void *) set;
|
chunk->aset = (void *) set;
|
||||||
return AllocChunkGetPointer(chunk);
|
return AllocChunkGetPointer(chunk);
|
||||||
@ -241,22 +256,23 @@ AllocSetAlloc(AllocSet set, Size size)
|
|||||||
Assert(chunk_size >= size);
|
Assert(chunk_size >= size);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If there is enough room in the active allocation block, always
|
* If there is enough room in the active allocation block, *and*
|
||||||
* allocate the chunk there.
|
* the chunk is less than ALLOC_BIGCHUNK_LIMIT, put the chunk
|
||||||
|
* into the active allocation block.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
if ((block = set->blocks) != NULL)
|
if ((block = set->blocks) != NULL)
|
||||||
{
|
{
|
||||||
Size have_free = block->endptr - block->freeptr;
|
Size have_free = block->endptr - block->freeptr;
|
||||||
|
|
||||||
if (have_free < (chunk_size + ALLOC_CHUNKHDRSZ))
|
if (have_free < (chunk_size + ALLOC_CHUNKHDRSZ) ||
|
||||||
|
chunk_size >= ALLOC_BIGCHUNK_LIMIT)
|
||||||
block = NULL;
|
block = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Otherwise, if requested size exceeds smallchunk limit, allocate an
|
* Otherwise, if requested size exceeds smallchunk limit, allocate an
|
||||||
* entire separate block for this allocation
|
* entire separate block for this allocation. In particular, we will
|
||||||
*
|
* always take this path if the requested size exceeds bigchunk limit.
|
||||||
*/
|
*/
|
||||||
if (block == NULL && size > ALLOC_SMALLCHUNK_LIMIT)
|
if (block == NULL && size > ALLOC_SMALLCHUNK_LIMIT)
|
||||||
{
|
{
|
||||||
@ -290,7 +306,7 @@ AllocSetAlloc(AllocSet set, Size size)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Time to create a new regular block?
|
* Time to create a new regular (multi-chunk) block?
|
||||||
*/
|
*/
|
||||||
if (block == NULL)
|
if (block == NULL)
|
||||||
{
|
{
|
||||||
@ -364,7 +380,6 @@ AllocSetAlloc(AllocSet set, Size size)
|
|||||||
void
|
void
|
||||||
AllocSetFree(AllocSet set, AllocPointer pointer)
|
AllocSetFree(AllocSet set, AllocPointer pointer)
|
||||||
{
|
{
|
||||||
int fidx;
|
|
||||||
AllocChunk chunk;
|
AllocChunk chunk;
|
||||||
|
|
||||||
/* AssertArg(AllocSetIsValid(set)); */
|
/* AssertArg(AllocSetIsValid(set)); */
|
||||||
@ -372,10 +387,42 @@ AllocSetFree(AllocSet set, AllocPointer pointer)
|
|||||||
AssertArg(AllocSetContains(set, pointer));
|
AssertArg(AllocSetContains(set, pointer));
|
||||||
|
|
||||||
chunk = AllocPointerGetChunk(pointer);
|
chunk = AllocPointerGetChunk(pointer);
|
||||||
fidx = AllocSetFreeIndex(chunk->size);
|
|
||||||
|
if (chunk->size >= ALLOC_BIGCHUNK_LIMIT)
|
||||||
|
{
|
||||||
|
/* Big chunks are certain to have been allocated as single-chunk
|
||||||
|
* blocks. Find the containing block and return it to malloc().
|
||||||
|
*/
|
||||||
|
AllocBlock block = set->blocks;
|
||||||
|
AllocBlock prevblock = NULL;
|
||||||
|
|
||||||
|
while (block != NULL)
|
||||||
|
{
|
||||||
|
if (chunk == (AllocChunk) (((char *) block) + ALLOC_BLOCKHDRSZ))
|
||||||
|
break;
|
||||||
|
prevblock = block;
|
||||||
|
block = block->next;
|
||||||
|
}
|
||||||
|
if (block == NULL)
|
||||||
|
elog(ERROR, "AllocSetFree: cannot find block containing chunk");
|
||||||
|
/* let's just make sure chunk is the only one in the block */
|
||||||
|
Assert(block->freeptr == ((char *) block) +
|
||||||
|
(chunk->size + ALLOC_BLOCKHDRSZ + ALLOC_CHUNKHDRSZ));
|
||||||
|
/* OK, remove block from aset's list and free it */
|
||||||
|
if (prevblock == NULL)
|
||||||
|
set->blocks = block->next;
|
||||||
|
else
|
||||||
|
prevblock->next = block->next;
|
||||||
|
free(block);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* Normal case, put the chunk into appropriate freelist */
|
||||||
|
int fidx = AllocSetFreeIndex(chunk->size);
|
||||||
|
|
||||||
chunk->aset = (void *) set->freelist[fidx];
|
chunk->aset = (void *) set->freelist[fidx];
|
||||||
set->freelist[fidx] = chunk;
|
set->freelist[fidx] = chunk;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -393,7 +440,6 @@ AllocSetFree(AllocSet set, AllocPointer pointer)
|
|||||||
AllocPointer
|
AllocPointer
|
||||||
AllocSetRealloc(AllocSet set, AllocPointer pointer, Size size)
|
AllocSetRealloc(AllocSet set, AllocPointer pointer, Size size)
|
||||||
{
|
{
|
||||||
AllocPointer newPointer;
|
|
||||||
Size oldsize;
|
Size oldsize;
|
||||||
|
|
||||||
/* AssertArg(AllocSetIsValid(set)); */
|
/* AssertArg(AllocSetIsValid(set)); */
|
||||||
@ -402,23 +448,70 @@ AllocSetRealloc(AllocSet set, AllocPointer pointer, Size size)
|
|||||||
|
|
||||||
/*
|
/*
|
||||||
* Chunk sizes are aligned to power of 2 on AllocSetAlloc(). Maybe the
|
* Chunk sizes are aligned to power of 2 on AllocSetAlloc(). Maybe the
|
||||||
* allocated area already is >= the new size.
|
* allocated area already is >= the new size. (In particular, we
|
||||||
*
|
* always fall out here if the requested size is a decrease.)
|
||||||
*/
|
*/
|
||||||
oldsize = AllocPointerGetSize(pointer);
|
oldsize = AllocPointerGetSize(pointer);
|
||||||
if (oldsize >= size)
|
if (oldsize >= size)
|
||||||
return pointer;
|
return pointer;
|
||||||
|
|
||||||
/* allocate new pointer */
|
if (oldsize >= ALLOC_BIGCHUNK_LIMIT)
|
||||||
newPointer = AllocSetAlloc(set, size);
|
{
|
||||||
|
/*
|
||||||
|
* If the chunk is already >= bigchunk limit, then it must have been
|
||||||
|
* allocated as a single-chunk block. Find the containing block and
|
||||||
|
* use realloc() to make it bigger with minimum space wastage.
|
||||||
|
*/
|
||||||
|
AllocChunk chunk = AllocPointerGetChunk(pointer);
|
||||||
|
AllocBlock block = set->blocks;
|
||||||
|
AllocBlock prevblock = NULL;
|
||||||
|
Size blksize;
|
||||||
|
|
||||||
/* fill new memory */
|
while (block != NULL)
|
||||||
memmove(newPointer, pointer, (oldsize < size) ? oldsize : size);
|
{
|
||||||
|
if (chunk == (AllocChunk) (((char *) block) + ALLOC_BLOCKHDRSZ))
|
||||||
|
break;
|
||||||
|
prevblock = block;
|
||||||
|
block = block->next;
|
||||||
|
}
|
||||||
|
if (block == NULL)
|
||||||
|
elog(ERROR, "AllocSetRealloc: cannot find block containing chunk");
|
||||||
|
/* let's just make sure chunk is the only one in the block */
|
||||||
|
Assert(block->freeptr == ((char *) block) +
|
||||||
|
(chunk->size + ALLOC_BLOCKHDRSZ + ALLOC_CHUNKHDRSZ));
|
||||||
|
|
||||||
/* free old pointer */
|
/* Do the realloc */
|
||||||
|
size = MAXALIGN(size);
|
||||||
|
blksize = size + ALLOC_BLOCKHDRSZ + ALLOC_CHUNKHDRSZ;
|
||||||
|
block = (AllocBlock) realloc(block, blksize);
|
||||||
|
if (block == NULL)
|
||||||
|
elog(FATAL, "Memory exhausted in AllocSetReAlloc()");
|
||||||
|
block->freeptr = block->endptr = ((char *) block) + blksize;
|
||||||
|
|
||||||
|
/* Update pointers since block has likely been moved */
|
||||||
|
chunk = (AllocChunk) (((char *) block) + ALLOC_BLOCKHDRSZ);
|
||||||
|
if (prevblock == NULL)
|
||||||
|
set->blocks = block;
|
||||||
|
else
|
||||||
|
prevblock->next = block;
|
||||||
|
chunk->size = size;
|
||||||
|
return AllocChunkGetPointer(chunk);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* Normal small-chunk case: just do it by brute force. */
|
||||||
|
|
||||||
|
/* allocate new chunk */
|
||||||
|
AllocPointer newPointer = AllocSetAlloc(set, size);
|
||||||
|
|
||||||
|
/* transfer existing data (certain to fit) */
|
||||||
|
memcpy(newPointer, pointer, oldsize);
|
||||||
|
|
||||||
|
/* free old chunk */
|
||||||
AllocSetFree(set, pointer);
|
AllocSetFree(set, pointer);
|
||||||
|
|
||||||
return newPointer;
|
return newPointer;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -15,7 +15,7 @@
|
|||||||
*
|
*
|
||||||
* Copyright (c) 1994, Regents of the University of California
|
* Copyright (c) 1994, Regents of the University of California
|
||||||
*
|
*
|
||||||
* $Id: memutils.h,v 1.30 1999/07/15 15:21:41 momjian Exp $
|
* $Id: memutils.h,v 1.31 1999/08/24 20:11:19 tgl Exp $
|
||||||
*
|
*
|
||||||
* NOTES
|
* NOTES
|
||||||
* some of the information in this file will be moved to
|
* some of the information in this file will be moved to
|
||||||
@ -101,6 +101,12 @@ extern void OrderedElemPushInto(OrderedElem elem, OrderedSet Set);
|
|||||||
* reallocated. In addition, an allocation set may be reset which
|
* reallocated. In addition, an allocation set may be reset which
|
||||||
* will cause all memory allocated within it to be freed.
|
* will cause all memory allocated within it to be freed.
|
||||||
*
|
*
|
||||||
|
* XXX The following material about allocation modes is all OUT OF DATE.
|
||||||
|
* aset.c currently implements only one allocation strategy,
|
||||||
|
* DynamicAllocMode, and that's the only one anyone ever requests anyway.
|
||||||
|
* If we ever did have more strategies, the new ones might or might
|
||||||
|
* not look like what is described here...
|
||||||
|
*
|
||||||
* Allocations may occur in four different modes. The mode of
|
* Allocations may occur in four different modes. The mode of
|
||||||
* allocation does not affect the behavior of allocations except in
|
* allocation does not affect the behavior of allocations except in
|
||||||
* terms of performance. The allocation mode is set at the time of
|
* terms of performance. The allocation mode is set at the time of
|
||||||
@ -146,7 +152,7 @@ typedef Pointer AllocPointer;
|
|||||||
* Mode of allocation for an allocation set.
|
* Mode of allocation for an allocation set.
|
||||||
*
|
*
|
||||||
* Note:
|
* Note:
|
||||||
* See above for a description of the various nodes.
|
* See above for a description of the various modes.
|
||||||
*/
|
*/
|
||||||
typedef enum AllocMode
|
typedef enum AllocMode
|
||||||
{
|
{
|
||||||
@ -158,23 +164,42 @@ typedef enum AllocMode
|
|||||||
|
|
||||||
#define DefaultAllocMode DynamicAllocMode
|
#define DefaultAllocMode DynamicAllocMode
|
||||||
|
|
||||||
|
typedef struct AllocSetData *AllocSet;
|
||||||
|
typedef struct AllocBlockData *AllocBlock;
|
||||||
|
typedef struct AllocChunkData *AllocChunk;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* AllocSet
|
||||||
|
* Allocation set.
|
||||||
|
*/
|
||||||
|
typedef struct AllocSetData
|
||||||
|
{
|
||||||
|
AllocBlock blocks; /* head of list of blocks in this set */
|
||||||
|
#define ALLOCSET_NUM_FREELISTS 8
|
||||||
|
AllocChunk freelist[ALLOCSET_NUM_FREELISTS]; /* free chunk lists */
|
||||||
|
/* Note: this will change in the future to support other modes */
|
||||||
|
} AllocSetData;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* AllocBlock
|
* AllocBlock
|
||||||
* Small pieces of memory are taken from bigger blocks of
|
* An AllocBlock is the unit of memory that is obtained by aset.c
|
||||||
* memory with a size aligned to a power of two. These
|
* from malloc(). It contains one or more AllocChunks, which are
|
||||||
* pieces are not free's separately, instead they are reused
|
* the units requested by palloc() and freed by pfree(). AllocChunks
|
||||||
* for the next allocation of a fitting size.
|
* cannot be returned to malloc() individually, instead they are put
|
||||||
|
* on freelists by pfree() and re-used by the next palloc() that has
|
||||||
|
* a matching request size.
|
||||||
|
*
|
||||||
|
* AllocBlockData is the header data for a block --- the usable space
|
||||||
|
* within the block begins at the next alignment boundary.
|
||||||
*/
|
*/
|
||||||
typedef struct AllocBlockData
|
typedef struct AllocBlockData
|
||||||
{
|
{
|
||||||
struct AllocSetData *aset;
|
AllocSet aset; /* aset that owns this block */
|
||||||
struct AllocBlockData *next;
|
AllocBlock next; /* next block in aset's blocks list */
|
||||||
char *freeptr;
|
char *freeptr; /* start of free space in this block */
|
||||||
char *endptr;
|
char *endptr; /* end of space in this block */
|
||||||
} AllocBlockData;
|
} AllocBlockData;
|
||||||
|
|
||||||
typedef AllocBlockData *AllocBlock;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* AllocChunk
|
* AllocChunk
|
||||||
* The prefix of each piece of memory in an AllocBlock
|
* The prefix of each piece of memory in an AllocBlock
|
||||||
@ -183,26 +208,10 @@ typedef struct AllocChunkData
|
|||||||
{
|
{
|
||||||
/* aset is the owning aset if allocated, or the freelist link if free */
|
/* aset is the owning aset if allocated, or the freelist link if free */
|
||||||
void *aset;
|
void *aset;
|
||||||
/* size is always the chunk size */
|
/* size is always the size of the usable space in the chunk */
|
||||||
Size size;
|
Size size;
|
||||||
} AllocChunkData;
|
} AllocChunkData;
|
||||||
|
|
||||||
typedef AllocChunkData *AllocChunk;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* AllocSet
|
|
||||||
* Allocation set.
|
|
||||||
*/
|
|
||||||
typedef struct AllocSetData
|
|
||||||
{
|
|
||||||
struct AllocBlockData *blocks;
|
|
||||||
#define ALLOCSET_NUM_FREELISTS 8
|
|
||||||
struct AllocChunkData *freelist[ALLOCSET_NUM_FREELISTS];
|
|
||||||
/* Note: this will change in the future to support other modes */
|
|
||||||
} AllocSetData;
|
|
||||||
|
|
||||||
typedef AllocSetData *AllocSet;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* AllocPointerIsValid
|
* AllocPointerIsValid
|
||||||
* True iff pointer is valid allocation pointer.
|
* True iff pointer is valid allocation pointer.
|
||||||
|
Loading…
x
Reference in New Issue
Block a user