Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
Skip to content

Commit c22dea8

Browse files
committed
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.
1 parent 6bb7b46 commit c22dea8

File tree

1 file changed

+21
-6
lines changed

1 file changed

+21
-6
lines changed

src/backend/utils/mmgr/aset.c

Lines changed: 21 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
* Portions Copyright (c) 1994, Regents of the University of California
1212
*
1313
* IDENTIFICATION
14-
* $PostgreSQL: pgsql/src/backend/utils/mmgr/aset.c,v 1.69 2006/11/08 19:27:24 tgl Exp $
14+
* $PostgreSQL: pgsql/src/backend/utils/mmgr/aset.c,v 1.70 2006/12/27 22:30:48 tgl Exp $
1515
*
1616
* NOTE:
1717
* This is a new (Feb. 05, 1999) implementation of the allocation set
@@ -141,6 +141,7 @@ typedef struct AllocSetContext
141141
Size initBlockSize; /* initial block size */
142142
Size maxBlockSize; /* maximum block size */
143143
Size nextBlockSize; /* next block size to allocate */
144+
Size allocChunkLimit; /* effective chunk size limit */
144145
AllocBlock keeper; /* if not NULL, keep this block over resets */
145146
} AllocSetContext;
146147

@@ -328,6 +329,20 @@ AllocSetContextCreate(MemoryContext parent,
328329
context->maxBlockSize = maxBlockSize;
329330
context->nextBlockSize = initBlockSize;
330331

332+
/*
333+
* Compute the allocation chunk size limit for this context. It can't
334+
* be more than ALLOC_CHUNK_LIMIT because of the fixed number of
335+
* freelists. If maxBlockSize is small then requests exceeding the
336+
* maxBlockSize should be treated as large chunks, too. We have to
337+
* have allocChunkLimit a power of two, because the requested and
338+
* actually-allocated sizes of any chunk must be on the same side of
339+
* the limit, else we get confused about whether the chunk is "big".
340+
*/
341+
context->allocChunkLimit = ALLOC_CHUNK_LIMIT;
342+
while (context->allocChunkLimit >
343+
(Size) (maxBlockSize - ALLOC_BLOCKHDRSZ - ALLOC_CHUNKHDRSZ))
344+
context->allocChunkLimit >>= 1;
345+
331346
/*
332347
* Grab always-allocated space, if requested
333348
*/
@@ -512,7 +527,7 @@ AllocSetAlloc(MemoryContext context, Size size)
512527
* If requested size exceeds maximum for chunks, allocate an entire block
513528
* for this request.
514529
*/
515-
if (size > ALLOC_CHUNK_LIMIT)
530+
if (size > set->allocChunkLimit)
516531
{
517532
chunk_size = MAXALIGN(size);
518533
blksize = chunk_size + ALLOC_BLOCKHDRSZ + ALLOC_CHUNKHDRSZ;
@@ -775,7 +790,7 @@ AllocSetFree(MemoryContext context, void *pointer)
775790
set->header.name, chunk);
776791
#endif
777792

778-
if (chunk->size > ALLOC_CHUNK_LIMIT)
793+
if (chunk->size > set->allocChunkLimit)
779794
{
780795
/*
781796
* Big chunks are certain to have been allocated as single-chunk
@@ -868,7 +883,7 @@ AllocSetRealloc(MemoryContext context, void *pointer, Size size)
868883
return pointer;
869884
}
870885

871-
if (oldsize > ALLOC_CHUNK_LIMIT)
886+
if (oldsize > set->allocChunkLimit)
872887
{
873888
/*
874889
* The chunk must have been allocated as a single-chunk block. Find
@@ -943,7 +958,7 @@ AllocSetRealloc(MemoryContext context, void *pointer, Size size)
943958
*/
944959
AllocPointer newPointer;
945960

946-
if (size <= ALLOC_CHUNK_LIMIT)
961+
if (size <= set->allocChunkLimit)
947962
{
948963
AllocBlock block = set->blocks;
949964
char *chunk_end;
@@ -1122,7 +1137,7 @@ AllocSetCheck(MemoryContext context)
11221137
name, (unsigned long) chsize, chunk, block);
11231138

11241139
/* single-chunk block? */
1125-
if (chsize > ALLOC_CHUNK_LIMIT &&
1140+
if (chsize > set->allocChunkLimit &&
11261141
chsize + ALLOC_CHUNKHDRSZ != blk_used)
11271142
elog(WARNING, "problem in alloc set %s: bad single-chunk %p in block %p",
11281143
name, chunk, block);

0 commit comments

Comments
 (0)