83 #define ALLOC_MINBITS 3
84 #define ALLOCSET_NUM_FREELISTS 11
85 #define ALLOC_CHUNK_LIMIT (1 << (ALLOCSET_NUM_FREELISTS-1+ALLOC_MINBITS))
87 #define ALLOC_CHUNK_FRACTION 4
104 #define ALLOC_BLOCKHDRSZ MAXALIGN(sizeof(AllocBlockData))
105 #define ALLOC_CHUNKHDRSZ sizeof(MemoryChunk)
132 #define GetFreeListLink(chkptr) \
133 (AllocFreeListLink *) ((char *) (chkptr) + ALLOC_CHUNKHDRSZ)
136 #define FreeListIdxIsValid(fidx) \
137 ((fidx) >= 0 && (fidx) < ALLOCSET_NUM_FREELISTS)
140 #define GetChunkSizeFromFreeListIdx(fidx) \
141 ((((Size) 1) << ALLOC_MINBITS) << (fidx))
194 #define AllocPointerIsValid(pointer) PointerIsValid(pointer)
200 #define AllocSetIsValid(set) \
201 (PointerIsValid(set) && IsA(set, AllocSetContext))
207 #define AllocBlockIsValid(block) \
208 (PointerIsValid(block) && AllocSetIsValid((block)->aset))
215 #define ExternalChunkGetBlock(chunk) \
216 (AllocBlock) ((char *) chunk - ALLOC_BLOCKHDRSZ)
241 #define MAX_FREE_CONTEXTS 100
244 #define KeeperBlock(set) \
245 ((AllocBlock) (((char *) set) + MAXALIGN(sizeof(AllocSetContext))))
248 #define IsKeeperBlock(set, block) ((block) == (KeeperBlock(set)))
300 #ifdef HAVE_BITSCAN_REVERSE
308 "ALLOC_CHUNK_LIMIT must be less than 64kB");
360 "sizeof(MemoryChunk) is not maxaligned");
363 "sizeof(AllocFreeListLink) larger than minimum allocation size");
378 initBlockSize >= 1024);
380 maxBlockSize >= initBlockSize &&
382 Assert(minContextSize == 0 ||
383 (minContextSize ==
MAXALIGN(minContextSize) &&
384 minContextSize >= 1024 &&
385 minContextSize <= maxBlockSize));
404 if (freeListIndex >= 0)
435 if (minContextSize != 0)
436 firstBlockSize =
Max(firstBlockSize, minContextSize);
438 firstBlockSize =
Max(firstBlockSize, initBlockSize);
450 (
errcode(ERRCODE_OUT_OF_MEMORY),
452 errdetail(
"Failed while creating memory context \"%s\".",
465 block->
endptr = ((
char *) set) + firstBlockSize;
496 "ALLOC_CHUNK_LIMIT != ALLOCSET_SEPARATE_THRESHOLD");
545 #ifdef MEMORY_CONTEXT_CHECKING
551 keepersize =
KeeperBlock(set)->endptr - ((
char *) set);
561 while (block != NULL)
570 #ifdef CLOBBER_FREED_MEMORY
571 wipe_mem(datastart, block->
freeptr - datastart);
585 #ifdef CLOBBER_FREED_MEMORY
586 wipe_mem(block, block->
freeptr - ((
char *) block));
615 #ifdef MEMORY_CONTEXT_CHECKING
621 keepersize =
KeeperBlock(set)->endptr - ((
char *) set);
666 while (block != NULL)
673 #ifdef CLOBBER_FREED_MEMORY
674 wipe_mem(block, block->
freeptr - ((
char *) block));
707 #ifdef MEMORY_CONTEXT_CHECKING
719 context->mem_allocated += blksize;
729 #ifdef MEMORY_CONTEXT_CHECKING
735 #ifdef RANDOMIZE_ALLOCATED_MEMORY
790 #ifdef MEMORY_CONTEXT_CHECKING
793 if (
size < chunk_size)
796 #ifdef RANDOMIZE_ALLOCATED_MEMORY
873 #ifdef MEMORY_CONTEXT_CHECKING
904 while (blksize < required_size)
914 while (block == NULL && blksize > 1024 * 1024)
917 if (blksize < required_size)
925 context->mem_allocated += blksize;
929 block->
endptr = ((
char *) block) + blksize;
1016 #ifdef MEMORY_CONTEXT_CHECKING
1022 #ifdef RANDOMIZE_ALLOCATED_MEMORY
1084 #ifdef MEMORY_CONTEXT_CHECKING
1088 if (!sentinel_ok(pointer,
chunk->requested_size))
1089 elog(
WARNING,
"detected write past chunk end in %s %p",
1104 #ifdef CLOBBER_FREED_MEMORY
1105 wipe_mem(block, block->
freeptr - ((
char *) block));
1128 #ifdef MEMORY_CONTEXT_CHECKING
1131 if (!sentinel_ok(pointer,
chunk->requested_size))
1132 elog(
WARNING,
"detected write past chunk end in %s %p",
1136 #ifdef CLOBBER_FREED_MEMORY
1145 #ifdef MEMORY_CONTEXT_CHECKING
1205 oldchksize = block->
endptr - (
char *) pointer;
1207 #ifdef MEMORY_CONTEXT_CHECKING
1210 if (!sentinel_ok(pointer,
chunk->requested_size))
1211 elog(
WARNING,
"detected write past chunk end in %s %p",
1215 #ifdef MEMORY_CONTEXT_CHECKING
1224 oldblksize = block->
endptr - ((
char *) block);
1238 block->
freeptr = block->
endptr = ((
char *) block) + blksize;
1246 set->blocks = block;
1250 #ifdef MEMORY_CONTEXT_CHECKING
1251 #ifdef RANDOMIZE_ALLOCATED_MEMORY
1258 randomize_mem((
char *) pointer +
chunk->requested_size,
1280 set_sentinel(pointer,
size);
1318 #ifdef MEMORY_CONTEXT_CHECKING
1320 if (
chunk->requested_size < oldchksize)
1321 if (!sentinel_ok(pointer,
chunk->requested_size))
1322 elog(
WARNING,
"detected write past chunk end in %s %p",
1331 if (oldchksize >=
size)
1333 #ifdef MEMORY_CONTEXT_CHECKING
1334 Size oldrequest =
chunk->requested_size;
1336 #ifdef RANDOMIZE_ALLOCATED_MEMORY
1338 if (
size > oldrequest)
1339 randomize_mem((
char *) pointer + oldrequest,
1349 if (
size > oldrequest)
1357 if (
size < oldchksize)
1358 set_sentinel(pointer,
size);
1395 if (newPointer == NULL)
1411 #ifdef MEMORY_CONTEXT_CHECKING
1412 oldsize =
chunk->requested_size;
1414 oldsize = oldchksize;
1419 memcpy(newPointer, pointer, oldsize);
1527 Size freechunks = 0;
1538 for (block = set->
blocks; block != NULL; block = block->
next)
1541 totalspace += block->
endptr - ((
char *) block);
1549 while (
chunk != NULL)
1569 char stats_string[200];
1571 snprintf(stats_string,
sizeof(stats_string),
1572 "%zu total in %zu blocks; %zu free (%zu chunks); %zu used",
1573 totalspace, nblocks, freespace, freechunks,
1574 totalspace - freespace);
1575 printfunc(
context, passthru, stats_string, print_to_stderr);
1588 #ifdef MEMORY_CONTEXT_CHECKING
1605 Size total_allocated = 0;
1607 for (prevblock = NULL, block = set->
blocks;
1609 prevblock = block, block = block->
next)
1612 long blk_used = block->
freeptr - bpoz;
1615 bool has_external_chunk =
false;
1618 total_allocated += block->
endptr - ((
char *) set);
1620 total_allocated += block->
endptr - ((
char *) block);
1628 elog(
WARNING,
"problem in alloc set %s: empty block %p",
1635 if (block->
aset != set ||
1636 block->
prev != prevblock ||
1639 elog(
WARNING,
"problem in alloc set %s: corrupt header in block %p",
1645 while (bpoz < block->freeptr)
1657 has_external_chunk =
true;
1661 elog(
WARNING,
"problem in alloc set %s: bad single-chunk %p in block %p",
1669 elog(
WARNING,
"problem in alloc set %s: bad chunk size for chunk %p in block %p",
1679 elog(
WARNING,
"problem in alloc set %s: bad block offset for chunk %p in block %p",
1682 dsize =
chunk->requested_size;
1686 elog(
WARNING,
"problem in alloc set %s: req size > alloc size for chunk %p in block %p",
1691 elog(
WARNING,
"problem in alloc set %s: bad size %zu for chunk %p in block %p",
1699 elog(
WARNING,
"problem in alloc set %s: detected write past chunk end in block %p, chunk %p",
1713 elog(
WARNING,
"problem in alloc set %s: found inconsistent memory block %p",
1716 if (has_external_chunk && nchunks > 1)
1717 elog(
WARNING,
"problem in alloc set %s: external chunk on non-dedicated block %p",
Datum idx(PG_FUNCTION_ARGS)
void AllocSetReset(MemoryContext context)
void * AllocSetRealloc(void *pointer, Size size, int flags)
#define AllocSetIsValid(set)
#define AllocBlockIsValid(block)
#define IsKeeperBlock(set, block)
#define GetFreeListLink(chkptr)
#define FreeListIdxIsValid(fidx)
Size AllocSetGetChunkSpace(void *pointer)
MemoryContext AllocSetGetChunkContext(void *pointer)
void AllocSetStats(MemoryContext context, MemoryStatsPrintFunc printfunc, void *passthru, MemoryContextCounters *totals, bool print_to_stderr)
static void * AllocSetAllocChunkFromBlock(MemoryContext context, AllocBlock block, Size size, Size chunk_size, int fidx)
void * AllocSetAlloc(MemoryContext context, Size size, int flags)
#define GetChunkSizeFromFreeListIdx(fidx)
struct AllocBlockData * AllocBlock
#define MAX_FREE_CONTEXTS
static int AllocSetFreeIndex(Size size)
static pg_noinline void * AllocSetAllocFromNewBlock(MemoryContext context, Size size, int flags, int fidx)
bool AllocSetIsEmpty(MemoryContext context)
struct AllocBlockData AllocBlockData
#define ALLOCSET_NUM_FREELISTS
struct AllocSetContext AllocSetContext
#define ALLOC_CHUNK_FRACTION
void AllocSetFree(void *pointer)
static pg_noinline void * AllocSetAllocLarge(MemoryContext context, Size size, int flags)
void AllocSetDelete(MemoryContext context)
struct AllocSetFreeList AllocSetFreeList
#define ALLOC_CHUNK_LIMIT
struct AllocFreeListLink AllocFreeListLink
static AllocSetFreeList context_freelists[2]
#define ExternalChunkGetBlock(chunk)
MemoryContext AllocSetContextCreateInternal(MemoryContext parent, const char *name, Size minContextSize, Size initBlockSize, Size maxBlockSize)
AllocSetContext * AllocSet
#define PG_USED_FOR_ASSERTS_ONLY
#define Assert(condition)
#define MemSetAligned(start, val, len)
#define StaticAssertDecl(condition, errmessage)
#define StaticAssertStmt(condition, errmessage)
int errdetail(const char *fmt,...)
int errcode(int sqlerrcode)
int errmsg(const char *fmt,...)
#define ereport(elevel,...)
void MemoryContextCreate(MemoryContext node, NodeTag tag, MemoryContextMethodID method_id, MemoryContext parent, const char *name)
MemoryContext TopMemoryContext
void MemoryContextStats(MemoryContext context)
void * MemoryContextAllocationFailure(MemoryContext context, Size size, int flags)
void MemoryContextResetOnly(MemoryContext context)
#define VALGRIND_MAKE_MEM_DEFINED(addr, size)
#define VALGRIND_MAKE_MEM_NOACCESS(addr, size)
#define VALGRIND_MAKE_MEM_UNDEFINED(addr, size)
void(* MemoryStatsPrintFunc)(MemoryContext context, void *passthru, const char *stats_string, bool print_to_stderr)
#define ALLOCSET_SMALL_MINSIZE
#define ALLOCSET_DEFAULT_MINSIZE
#define AllocHugeSizeIsValid(size)
#define ALLOCSET_SEPARATE_THRESHOLD
#define ALLOCSET_SMALL_INITSIZE
#define ALLOCSET_DEFAULT_INITSIZE
static void MemoryContextCheckSize(MemoryContext context, Size size, int flags)
#define MEMORYCHUNK_MAX_BLOCKOFFSET
static Size MemoryChunkGetValue(MemoryChunk *chunk)
#define MemoryChunkGetPointer(c)
static bool MemoryChunkIsExternal(MemoryChunk *chunk)
static void MemoryChunkSetHdrMaskExternal(MemoryChunk *chunk, MemoryContextMethodID methodid)
static void * MemoryChunkGetBlock(MemoryChunk *chunk)
#define PointerGetMemoryChunk(p)
static void MemoryChunkSetHdrMask(MemoryChunk *chunk, void *block, Size value, MemoryContextMethodID methodid)
struct MemoryContextData * MemoryContext
static int pg_leftmost_one_pos32(uint32 word)
PGDLLIMPORT const uint8 pg_leftmost_one_pos[256]
static pg_noinline void Size size
MemoryChunk * freelist[ALLOCSET_NUM_FREELISTS]
AllocSetContext * first_free
int link(const char *src, const char *dst)