mirror of
https://git.postgresql.org/git/postgresql.git
synced 2026-02-11 21:17:35 +08:00
Commit 3e98c0bafb added pg_backend_memory_contexts view to display the memory contexts of the backend process. However its target process is limited to the backend that is accessing to the view. So this is not so convenient when investigating the local memory bloat of other backend process. To improve this situation, this commit adds pg_log_backend_memory_contexts() function that requests to log the memory contexts of the specified backend process. This information can be also collected by calling MemoryContextStats(TopMemoryContext) via a debugger. But this technique cannot be used in some environments because no debugger is available there. So, pg_log_backend_memory_contexts() allows us to see the memory contexts of specified backend more easily. Only superusers are allowed to request to log the memory contexts because allowing any users to issue this request at an unbounded rate would cause lots of log messages and which can lead to denial of service. On receipt of the request, at the next CHECK_FOR_INTERRUPTS(), the target backend logs its memory contexts at LOG_SERVER_ONLY level, so that these memory contexts will appear in the server log but not be sent to the client. It logs one message per memory context. Because if it buffers all memory contexts into StringInfo to log them as one message, which may require the buffer to be enlarged very much and lead to OOM error since there can be a large number of memory contexts in a backend. When a backend process is consuming huge memory, logging all its memory contexts might overrun available disk space. To prevent this, now this patch limits the number of child contexts to log per parent to 100. As with MemoryContextStats(), it supposes that practical cases where the log gets long will typically be huge numbers of siblings under the same parent context; while the additional debugging value from seeing details about individual siblings beyond 100 will not be large. There was another proposed patch to add the function to return the memory contexts of specified backend as the result sets, instead of logging them, in the discussion. However that patch is not included in this commit because it had several issues to address. Thanks to Tatsuhito Kasahara, Andres Freund, Tom Lane, Tomas Vondra, Michael Paquier, Kyotaro Horiguchi and Zhihong Yu for the discussion. Bump catalog version. Author: Atsushi Torikoshi Reviewed-by: Kyotaro Horiguchi, Zhihong Yu, Fujii Masao Discussion: https://postgr.es/m/0271f440ac77f2a4180e0e56ebd944d1@oss.nttdata.com
228 lines
7.7 KiB
C
228 lines
7.7 KiB
C
/*-------------------------------------------------------------------------
|
|
*
|
|
* memutils.h
|
|
* This file contains declarations for memory allocation utility
|
|
* functions. These are functions that are not quite widely used
|
|
* enough to justify going in utils/palloc.h, but are still part
|
|
* of the API of the memory management subsystem.
|
|
*
|
|
*
|
|
* Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group
|
|
* Portions Copyright (c) 1994, Regents of the University of California
|
|
*
|
|
* src/include/utils/memutils.h
|
|
*
|
|
*-------------------------------------------------------------------------
|
|
*/
|
|
#ifndef MEMUTILS_H
|
|
#define MEMUTILS_H
|
|
|
|
#include "nodes/memnodes.h"
|
|
|
|
|
|
/*
|
|
* MaxAllocSize, MaxAllocHugeSize
|
|
* Quasi-arbitrary limits on size of allocations.
|
|
*
|
|
* Note:
|
|
* There is no guarantee that smaller allocations will succeed, but
|
|
* larger requests will be summarily denied.
|
|
*
|
|
* palloc() enforces MaxAllocSize, chosen to correspond to the limiting size
|
|
* of varlena objects under TOAST. See VARSIZE_4B() and related macros in
|
|
* postgres.h. Many datatypes assume that any allocatable size can be
|
|
* represented in a varlena header. This limit also permits a caller to use
|
|
* an "int" variable for an index into or length of an allocation. Callers
|
|
* careful to avoid these hazards can access the higher limit with
|
|
* MemoryContextAllocHuge(). Both limits permit code to assume that it may
|
|
* compute twice an allocation's size without overflow.
|
|
*/
|
|
#define MaxAllocSize ((Size) 0x3fffffff) /* 1 gigabyte - 1 */
|
|
|
|
#define AllocSizeIsValid(size) ((Size) (size) <= MaxAllocSize)
|
|
|
|
#define MaxAllocHugeSize (SIZE_MAX / 2)
|
|
|
|
#define AllocHugeSizeIsValid(size) ((Size) (size) <= MaxAllocHugeSize)
|
|
|
|
|
|
/*
|
|
* Standard top-level memory contexts.
|
|
*
|
|
* Only TopMemoryContext and ErrorContext are initialized by
|
|
* MemoryContextInit() itself.
|
|
*/
|
|
extern PGDLLIMPORT MemoryContext TopMemoryContext;
|
|
extern PGDLLIMPORT MemoryContext ErrorContext;
|
|
extern PGDLLIMPORT MemoryContext PostmasterContext;
|
|
extern PGDLLIMPORT MemoryContext CacheMemoryContext;
|
|
extern PGDLLIMPORT MemoryContext MessageContext;
|
|
extern PGDLLIMPORT MemoryContext TopTransactionContext;
|
|
extern PGDLLIMPORT MemoryContext CurTransactionContext;
|
|
|
|
/* This is a transient link to the active portal's memory context: */
|
|
extern PGDLLIMPORT MemoryContext PortalContext;
|
|
|
|
/* Backwards compatibility macro */
|
|
#define MemoryContextResetAndDeleteChildren(ctx) MemoryContextReset(ctx)
|
|
|
|
|
|
/*
|
|
* Memory-context-type-independent functions in mcxt.c
|
|
*/
|
|
extern void MemoryContextInit(void);
|
|
extern void MemoryContextReset(MemoryContext context);
|
|
extern void MemoryContextDelete(MemoryContext context);
|
|
extern void MemoryContextResetOnly(MemoryContext context);
|
|
extern void MemoryContextResetChildren(MemoryContext context);
|
|
extern void MemoryContextDeleteChildren(MemoryContext context);
|
|
extern void MemoryContextSetIdentifier(MemoryContext context, const char *id);
|
|
extern void MemoryContextSetParent(MemoryContext context,
|
|
MemoryContext new_parent);
|
|
extern Size GetMemoryChunkSpace(void *pointer);
|
|
extern MemoryContext MemoryContextGetParent(MemoryContext context);
|
|
extern bool MemoryContextIsEmpty(MemoryContext context);
|
|
extern Size MemoryContextMemAllocated(MemoryContext context, bool recurse);
|
|
extern void MemoryContextStats(MemoryContext context);
|
|
extern void MemoryContextStatsDetail(MemoryContext context, int max_children,
|
|
bool print_to_stderr);
|
|
extern void MemoryContextAllowInCriticalSection(MemoryContext context,
|
|
bool allow);
|
|
|
|
#ifdef MEMORY_CONTEXT_CHECKING
|
|
extern void MemoryContextCheck(MemoryContext context);
|
|
#endif
|
|
extern bool MemoryContextContains(MemoryContext context, void *pointer);
|
|
|
|
/* Handy macro for copying and assigning context ID ... but note double eval */
|
|
#define MemoryContextCopyAndSetIdentifier(cxt, id) \
|
|
MemoryContextSetIdentifier(cxt, MemoryContextStrdup(cxt, id))
|
|
|
|
/*
|
|
* GetMemoryChunkContext
|
|
* Given a currently-allocated chunk, determine the context
|
|
* it belongs to.
|
|
*
|
|
* All chunks allocated by any memory context manager are required to be
|
|
* preceded by the corresponding MemoryContext stored, without padding, in the
|
|
* preceding sizeof(void*) bytes. A currently-allocated chunk must contain a
|
|
* backpointer to its owning context. The backpointer is used by pfree() and
|
|
* repalloc() to find the context to call.
|
|
*/
|
|
#ifndef FRONTEND
|
|
static inline MemoryContext
|
|
GetMemoryChunkContext(void *pointer)
|
|
{
|
|
MemoryContext context;
|
|
|
|
/*
|
|
* Try to detect bogus pointers handed to us, poorly though we can.
|
|
* Presumably, a pointer that isn't MAXALIGNED isn't pointing at an
|
|
* allocated chunk.
|
|
*/
|
|
Assert(pointer != NULL);
|
|
Assert(pointer == (void *) MAXALIGN(pointer));
|
|
|
|
/*
|
|
* OK, it's probably safe to look at the context.
|
|
*/
|
|
context = *(MemoryContext *) (((char *) pointer) - sizeof(void *));
|
|
|
|
AssertArg(MemoryContextIsValid(context));
|
|
|
|
return context;
|
|
}
|
|
#endif
|
|
|
|
/*
|
|
* This routine handles the context-type-independent part of memory
|
|
* context creation. It's intended to be called from context-type-
|
|
* specific creation routines, and noplace else.
|
|
*/
|
|
extern void MemoryContextCreate(MemoryContext node,
|
|
NodeTag tag,
|
|
const MemoryContextMethods *methods,
|
|
MemoryContext parent,
|
|
const char *name);
|
|
|
|
extern void HandleLogMemoryContextInterrupt(void);
|
|
extern void ProcessLogMemoryContextInterrupt(void);
|
|
|
|
/*
|
|
* Memory-context-type-specific functions
|
|
*/
|
|
|
|
/* aset.c */
|
|
extern MemoryContext AllocSetContextCreateInternal(MemoryContext parent,
|
|
const char *name,
|
|
Size minContextSize,
|
|
Size initBlockSize,
|
|
Size maxBlockSize);
|
|
|
|
/*
|
|
* This wrapper macro exists to check for non-constant strings used as context
|
|
* names; that's no longer supported. (Use MemoryContextSetIdentifier if you
|
|
* want to provide a variable identifier.)
|
|
*/
|
|
#ifdef HAVE__BUILTIN_CONSTANT_P
|
|
#define AllocSetContextCreate(parent, name, ...) \
|
|
(StaticAssertExpr(__builtin_constant_p(name), \
|
|
"memory context names must be constant strings"), \
|
|
AllocSetContextCreateInternal(parent, name, __VA_ARGS__))
|
|
#else
|
|
#define AllocSetContextCreate \
|
|
AllocSetContextCreateInternal
|
|
#endif
|
|
|
|
/* slab.c */
|
|
extern MemoryContext SlabContextCreate(MemoryContext parent,
|
|
const char *name,
|
|
Size blockSize,
|
|
Size chunkSize);
|
|
|
|
/* generation.c */
|
|
extern MemoryContext GenerationContextCreate(MemoryContext parent,
|
|
const char *name,
|
|
Size blockSize);
|
|
|
|
/*
|
|
* Recommended default alloc parameters, suitable for "ordinary" contexts
|
|
* that might hold quite a lot of data.
|
|
*/
|
|
#define ALLOCSET_DEFAULT_MINSIZE 0
|
|
#define ALLOCSET_DEFAULT_INITSIZE (8 * 1024)
|
|
#define ALLOCSET_DEFAULT_MAXSIZE (8 * 1024 * 1024)
|
|
#define ALLOCSET_DEFAULT_SIZES \
|
|
ALLOCSET_DEFAULT_MINSIZE, ALLOCSET_DEFAULT_INITSIZE, ALLOCSET_DEFAULT_MAXSIZE
|
|
|
|
/*
|
|
* Recommended alloc parameters for "small" contexts that are never expected
|
|
* to contain much data (for example, a context to contain a query plan).
|
|
*/
|
|
#define ALLOCSET_SMALL_MINSIZE 0
|
|
#define ALLOCSET_SMALL_INITSIZE (1 * 1024)
|
|
#define ALLOCSET_SMALL_MAXSIZE (8 * 1024)
|
|
#define ALLOCSET_SMALL_SIZES \
|
|
ALLOCSET_SMALL_MINSIZE, ALLOCSET_SMALL_INITSIZE, ALLOCSET_SMALL_MAXSIZE
|
|
|
|
/*
|
|
* Recommended alloc parameters for contexts that should start out small,
|
|
* but might sometimes grow big.
|
|
*/
|
|
#define ALLOCSET_START_SMALL_SIZES \
|
|
ALLOCSET_SMALL_MINSIZE, ALLOCSET_SMALL_INITSIZE, ALLOCSET_DEFAULT_MAXSIZE
|
|
|
|
|
|
/*
|
|
* Threshold above which a request in an AllocSet context is certain to be
|
|
* allocated separately (and thereby have constant allocation overhead).
|
|
* Few callers should be interested in this, but tuplesort/tuplestore need
|
|
* to know it.
|
|
*/
|
|
#define ALLOCSET_SEPARATE_THRESHOLD 8192
|
|
|
|
#define SLAB_DEFAULT_BLOCK_SIZE (8 * 1024)
|
|
#define SLAB_LARGE_BLOCK_SIZE (8 * 1024 * 1024)
|
|
|
|
#endif /* MEMUTILS_H */
|