Skip to content

Commit 162c951

Browse files
committed
Allocate freechunks bitmap as part of SlabContext
The bitmap used by SlabCheck to cross-check free chunks in a block used to be allocated for each SlabCheck call, and was never freed. The memory leak could be fixed by simply adding a pfree call, but it's actually a bad idea to do any allocations in SlabCheck at all as it assumes the state of the memory management as a whole is sane. So instead we allocate the bitmap as part of SlabContext, which means we don't need to do any allocations in SlabCheck and the bitmap goes away together with the SlabContext. Backpatch to 10, where the Slab context was introduced. Author: Tomas Vondra Reported-by: Andres Freund Reviewed-by: Tom Lane Backpatch-through: 10 Discussion: https://www.postgresql.org/message-id/20200116044119.g45f7pmgz4jmodxj%40alap3.anarazel.de
1 parent 0fca3d0 commit 162c951

File tree

1 file changed

+21
-7
lines changed

1 file changed

+21
-7
lines changed

src/backend/utils/mmgr/slab.c

Lines changed: 21 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,9 @@ typedef struct SlabContext
7171
int chunksPerBlock; /* number of chunks per block */
7272
int minFreeChunks; /* min number of free chunks in any block */
7373
int nblocks; /* number of blocks allocated */
74+
#ifdef MEMORY_CONTEXT_CHECKING
75+
bool *freechunks; /* bitmap of free chunks in a block */
76+
#endif
7477
/* blocks with free space, grouped by number of free chunks: */
7578
dlist_head freelist[FLEXIBLE_ARRAY_MEMBER];
7679
} SlabContext;
@@ -230,6 +233,15 @@ SlabContextCreate(MemoryContext parent,
230233
/* Size of the memory context header */
231234
headerSize = offsetof(SlabContext, freelist) + freelistSize;
232235

236+
#ifdef MEMORY_CONTEXT_CHECKING
237+
/*
238+
* With memory checking, we need to allocate extra space for the bitmap
239+
* of free chunks. The bitmap is an array of bools, so we don't need to
240+
* worry about alignment.
241+
*/
242+
headerSize += chunksPerBlock * sizeof(bool);
243+
#endif
244+
233245
slab = (SlabContext *) malloc(headerSize);
234246
if (slab == NULL)
235247
{
@@ -259,6 +271,12 @@ SlabContextCreate(MemoryContext parent,
259271
for (i = 0; i < (slab->chunksPerBlock + 1); i++)
260272
dlist_init(&slab->freelist[i]);
261273

274+
#ifdef MEMORY_CONTEXT_CHECKING
275+
/* set the freechunks pointer right after the freelists array */
276+
slab->freechunks
277+
= (bool *) slab + offsetof(SlabContext, freelist) + freelistSize;
278+
#endif
279+
262280
/* Finally, do the type-independent part of context creation */
263281
MemoryContextCreate((MemoryContext) slab,
264282
T_SlabContext,
@@ -694,14 +712,10 @@ SlabCheck(MemoryContext context)
694712
int i;
695713
SlabContext *slab = castNode(SlabContext, context);
696714
const char *name = slab->header.name;
697-
char *freechunks;
698715

699716
Assert(slab);
700717
Assert(slab->chunksPerBlock > 0);
701718

702-
/* bitmap of free chunks on a block */
703-
freechunks = palloc(slab->chunksPerBlock * sizeof(bool));
704-
705719
/* walk all the freelists */
706720
for (i = 0; i <= slab->chunksPerBlock; i++)
707721
{
@@ -724,7 +738,7 @@ SlabCheck(MemoryContext context)
724738
name, block->nfree, block, i);
725739

726740
/* reset the bitmap of free chunks for this block */
727-
memset(freechunks, 0, (slab->chunksPerBlock * sizeof(bool)));
741+
memset(slab->freechunks, 0, (slab->chunksPerBlock * sizeof(bool)));
728742
idx = block->firstFreeChunk;
729743

730744
/*
@@ -741,7 +755,7 @@ SlabCheck(MemoryContext context)
741755

742756
/* count the chunk as free, add it to the bitmap */
743757
nfree++;
744-
freechunks[idx] = true;
758+
slab->freechunks[idx] = true;
745759

746760
/* read index of the next free chunk */
747761
chunk = SlabBlockGetChunk(slab, block, idx);
@@ -752,7 +766,7 @@ SlabCheck(MemoryContext context)
752766
for (j = 0; j < slab->chunksPerBlock; j++)
753767
{
754768
/* non-zero bit in the bitmap means chunk the chunk is used */
755-
if (!freechunks[j])
769+
if (!slab->freechunks[j])
756770
{
757771
SlabChunk *chunk = SlabBlockGetChunk(slab, block, j);
758772

0 commit comments

Comments
 (0)