mirror of
https://git.postgresql.org/git/postgresql.git
synced 2024-08-22 15:03:22 +02:00
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
This commit is contained in:
parent
5ec7bd819c
commit
8c37e4469d
@ -71,6 +71,9 @@ typedef struct SlabContext
|
|||||||
int chunksPerBlock; /* number of chunks per block */
|
int chunksPerBlock; /* number of chunks per block */
|
||||||
int minFreeChunks; /* min number of free chunks in any block */
|
int minFreeChunks; /* min number of free chunks in any block */
|
||||||
int nblocks; /* number of blocks allocated */
|
int nblocks; /* number of blocks allocated */
|
||||||
|
#ifdef MEMORY_CONTEXT_CHECKING
|
||||||
|
bool *freechunks; /* bitmap of free chunks in a block */
|
||||||
|
#endif
|
||||||
/* blocks with free space, grouped by number of free chunks: */
|
/* blocks with free space, grouped by number of free chunks: */
|
||||||
dlist_head freelist[FLEXIBLE_ARRAY_MEMBER];
|
dlist_head freelist[FLEXIBLE_ARRAY_MEMBER];
|
||||||
} SlabContext;
|
} SlabContext;
|
||||||
@ -230,6 +233,15 @@ SlabContextCreate(MemoryContext parent,
|
|||||||
/* Size of the memory context header */
|
/* Size of the memory context header */
|
||||||
headerSize = offsetof(SlabContext, freelist) + freelistSize;
|
headerSize = offsetof(SlabContext, freelist) + freelistSize;
|
||||||
|
|
||||||
|
#ifdef MEMORY_CONTEXT_CHECKING
|
||||||
|
/*
|
||||||
|
* With memory checking, we need to allocate extra space for the bitmap
|
||||||
|
* of free chunks. The bitmap is an array of bools, so we don't need to
|
||||||
|
* worry about alignment.
|
||||||
|
*/
|
||||||
|
headerSize += chunksPerBlock * sizeof(bool);
|
||||||
|
#endif
|
||||||
|
|
||||||
slab = (SlabContext *) malloc(headerSize);
|
slab = (SlabContext *) malloc(headerSize);
|
||||||
if (slab == NULL)
|
if (slab == NULL)
|
||||||
{
|
{
|
||||||
@ -259,6 +271,12 @@ SlabContextCreate(MemoryContext parent,
|
|||||||
for (i = 0; i < (slab->chunksPerBlock + 1); i++)
|
for (i = 0; i < (slab->chunksPerBlock + 1); i++)
|
||||||
dlist_init(&slab->freelist[i]);
|
dlist_init(&slab->freelist[i]);
|
||||||
|
|
||||||
|
#ifdef MEMORY_CONTEXT_CHECKING
|
||||||
|
/* set the freechunks pointer right after the freelists array */
|
||||||
|
slab->freechunks
|
||||||
|
= (bool *) slab + offsetof(SlabContext, freelist) + freelistSize;
|
||||||
|
#endif
|
||||||
|
|
||||||
/* Finally, do the type-independent part of context creation */
|
/* Finally, do the type-independent part of context creation */
|
||||||
MemoryContextCreate((MemoryContext) slab,
|
MemoryContextCreate((MemoryContext) slab,
|
||||||
T_SlabContext,
|
T_SlabContext,
|
||||||
@ -694,14 +712,10 @@ SlabCheck(MemoryContext context)
|
|||||||
int i;
|
int i;
|
||||||
SlabContext *slab = castNode(SlabContext, context);
|
SlabContext *slab = castNode(SlabContext, context);
|
||||||
const char *name = slab->header.name;
|
const char *name = slab->header.name;
|
||||||
char *freechunks;
|
|
||||||
|
|
||||||
Assert(slab);
|
Assert(slab);
|
||||||
Assert(slab->chunksPerBlock > 0);
|
Assert(slab->chunksPerBlock > 0);
|
||||||
|
|
||||||
/* bitmap of free chunks on a block */
|
|
||||||
freechunks = palloc(slab->chunksPerBlock * sizeof(bool));
|
|
||||||
|
|
||||||
/* walk all the freelists */
|
/* walk all the freelists */
|
||||||
for (i = 0; i <= slab->chunksPerBlock; i++)
|
for (i = 0; i <= slab->chunksPerBlock; i++)
|
||||||
{
|
{
|
||||||
@ -724,7 +738,7 @@ SlabCheck(MemoryContext context)
|
|||||||
name, block->nfree, block, i);
|
name, block->nfree, block, i);
|
||||||
|
|
||||||
/* reset the bitmap of free chunks for this block */
|
/* reset the bitmap of free chunks for this block */
|
||||||
memset(freechunks, 0, (slab->chunksPerBlock * sizeof(bool)));
|
memset(slab->freechunks, 0, (slab->chunksPerBlock * sizeof(bool)));
|
||||||
idx = block->firstFreeChunk;
|
idx = block->firstFreeChunk;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -741,7 +755,7 @@ SlabCheck(MemoryContext context)
|
|||||||
|
|
||||||
/* count the chunk as free, add it to the bitmap */
|
/* count the chunk as free, add it to the bitmap */
|
||||||
nfree++;
|
nfree++;
|
||||||
freechunks[idx] = true;
|
slab->freechunks[idx] = true;
|
||||||
|
|
||||||
/* read index of the next free chunk */
|
/* read index of the next free chunk */
|
||||||
chunk = SlabBlockGetChunk(slab, block, idx);
|
chunk = SlabBlockGetChunk(slab, block, idx);
|
||||||
@ -752,7 +766,7 @@ SlabCheck(MemoryContext context)
|
|||||||
for (j = 0; j < slab->chunksPerBlock; j++)
|
for (j = 0; j < slab->chunksPerBlock; j++)
|
||||||
{
|
{
|
||||||
/* non-zero bit in the bitmap means chunk the chunk is used */
|
/* non-zero bit in the bitmap means chunk the chunk is used */
|
||||||
if (!freechunks[j])
|
if (!slab->freechunks[j])
|
||||||
{
|
{
|
||||||
SlabChunk *chunk = SlabBlockGetChunk(slab, block, j);
|
SlabChunk *chunk = SlabBlockGetChunk(slab, block, j);
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user