Improve memory management code to avoid inefficient behavior when a context
has a small maxBlockSize: the maximum request size that we will treat as a "chunk" needs to be limited to fit in maxBlockSize. Otherwise we will round up the request size to the next power of 2, wasting space, which is a bit pointless if we aren't going to make the blocks big enough to fit additional stuff in them. The example motivating this is local buffer management, which makes repeated allocations of 8K (one BLCKSZ buffer) in TopMemoryContext, which has maxBlockSize = 8K because for the most part allocations there are small. This leads to each local buffer actually eating 16K of space, which adds up when there are thousands of them. I intend to change localbuf.c to aggregate its requests, which will prevent this particular misbehavior, but it seems likely that similar scenarios could arise elsewhere, so fixing the core problem seems wise as well.
This commit is contained in:
parent
6bb7b467c0
commit
c22dea8900
@ -11,7 +11,7 @@
|
||||
* Portions Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $PostgreSQL: pgsql/src/backend/utils/mmgr/aset.c,v 1.69 2006/11/08 19:27:24 tgl Exp $
|
||||
* $PostgreSQL: pgsql/src/backend/utils/mmgr/aset.c,v 1.70 2006/12/27 22:30:48 tgl Exp $
|
||||
*
|
||||
* NOTE:
|
||||
* This is a new (Feb. 05, 1999) implementation of the allocation set
|
||||
@ -141,6 +141,7 @@ typedef struct AllocSetContext
|
||||
Size initBlockSize; /* initial block size */
|
||||
Size maxBlockSize; /* maximum block size */
|
||||
Size nextBlockSize; /* next block size to allocate */
|
||||
Size allocChunkLimit; /* effective chunk size limit */
|
||||
AllocBlock keeper; /* if not NULL, keep this block over resets */
|
||||
} AllocSetContext;
|
||||
|
||||
@ -328,6 +329,20 @@ AllocSetContextCreate(MemoryContext parent,
|
||||
context->maxBlockSize = maxBlockSize;
|
||||
context->nextBlockSize = initBlockSize;
|
||||
|
||||
/*
|
||||
* Compute the allocation chunk size limit for this context. It can't
|
||||
* be more than ALLOC_CHUNK_LIMIT because of the fixed number of
|
||||
* freelists. If maxBlockSize is small then requests exceeding the
|
||||
* maxBlockSize should be treated as large chunks, too. We have to
|
||||
* have allocChunkLimit a power of two, because the requested and
|
||||
* actually-allocated sizes of any chunk must be on the same side of
|
||||
* the limit, else we get confused about whether the chunk is "big".
|
||||
*/
|
||||
context->allocChunkLimit = ALLOC_CHUNK_LIMIT;
|
||||
while (context->allocChunkLimit >
|
||||
(Size) (maxBlockSize - ALLOC_BLOCKHDRSZ - ALLOC_CHUNKHDRSZ))
|
||||
context->allocChunkLimit >>= 1;
|
||||
|
||||
/*
|
||||
* Grab always-allocated space, if requested
|
||||
*/
|
||||
@ -512,7 +527,7 @@ AllocSetAlloc(MemoryContext context, Size size)
|
||||
* If requested size exceeds maximum for chunks, allocate an entire block
|
||||
* for this request.
|
||||
*/
|
||||
if (size > ALLOC_CHUNK_LIMIT)
|
||||
if (size > set->allocChunkLimit)
|
||||
{
|
||||
chunk_size = MAXALIGN(size);
|
||||
blksize = chunk_size + ALLOC_BLOCKHDRSZ + ALLOC_CHUNKHDRSZ;
|
||||
@ -775,7 +790,7 @@ AllocSetFree(MemoryContext context, void *pointer)
|
||||
set->header.name, chunk);
|
||||
#endif
|
||||
|
||||
if (chunk->size > ALLOC_CHUNK_LIMIT)
|
||||
if (chunk->size > set->allocChunkLimit)
|
||||
{
|
||||
/*
|
||||
* Big chunks are certain to have been allocated as single-chunk
|
||||
@ -868,7 +883,7 @@ AllocSetRealloc(MemoryContext context, void *pointer, Size size)
|
||||
return pointer;
|
||||
}
|
||||
|
||||
if (oldsize > ALLOC_CHUNK_LIMIT)
|
||||
if (oldsize > set->allocChunkLimit)
|
||||
{
|
||||
/*
|
||||
* The chunk must have been allocated as a single-chunk block. Find
|
||||
@ -943,7 +958,7 @@ AllocSetRealloc(MemoryContext context, void *pointer, Size size)
|
||||
*/
|
||||
AllocPointer newPointer;
|
||||
|
||||
if (size <= ALLOC_CHUNK_LIMIT)
|
||||
if (size <= set->allocChunkLimit)
|
||||
{
|
||||
AllocBlock block = set->blocks;
|
||||
char *chunk_end;
|
||||
@ -1122,7 +1137,7 @@ AllocSetCheck(MemoryContext context)
|
||||
name, (unsigned long) chsize, chunk, block);
|
||||
|
||||
/* single-chunk block? */
|
||||
if (chsize > ALLOC_CHUNK_LIMIT &&
|
||||
if (chsize > set->allocChunkLimit &&
|
||||
chsize + ALLOC_CHUNKHDRSZ != blk_used)
|
||||
elog(WARNING, "problem in alloc set %s: bad single-chunk %p in block %p",
|
||||
name, chunk, block);
|
||||
|
Loading…
x
Reference in New Issue
Block a user