Skip to content

PostgreSQL 内存管理深度解析

摘要

PostgreSQL 拥有精心设计的分层内存管理架构,包括进程本地内存上下文、共享内存、缓冲区缓存和查询执行内存。本文深入剖析 PostgreSQL 源码中的内存管理实现,涵盖内存上下文机制、共享内存初始化、缓冲区管理、查询内存分配策略等核心主题,帮助读者全面理解 PostgreSQL 如何高效管理内存资源。


1. PostgreSQL 内存架构总览

┌─────────────────────────────────────────────────────────────────────────────┐
│                          PostgreSQL 内存架构                                  │
├─────────────────────────────────────────────────────────────────────────────┤
│                                                                             │
│  ┌─────────────────────────────────────────────────────────────────────┐  │
│  │                        共享内存 (Shared Memory)                       │  │
│  │  ┌─────────────────┐  ┌─────────────────┐  ┌─────────────────────┐ │  │
│  │  │  缓冲区缓存      │  │  WAL 缓冲区     │  │  锁管理器           │ │  │
│  │  │  (8KB * N)     │  │  (16MB)         │  │  (Lightweight Locks)│ │  │
│  │  └─────────────────┘  └─────────────────┘  └─────────────────────┘ │  │
│  │  ┌─────────────────┐  ┌─────────────────┐  ┌─────────────────────┐ │  │
│  │  │  进程/连接信息   │  │  事务管理器      │  │  缓存表              │ │  │
│  │  │  (per backend) │  │  (XID, clog)    │  │  (syscache)         │ │  │
│  │  └─────────────────┘  └─────────────────┘  └─────────────────────┘ │  │
│  └─────────────────────────────────────────────────────────────────────┘  │
│                                                                             │
│  ┌─────────────────────────────────────────────────────────────────────┐  │
│  │                      进程本地内存 (Per-Backend)                        │  │
│  │  ┌─────────────────┐  ┌─────────────────┐  ┌─────────────────────┐ │  │
│  │  │  内存上下文     │  │  查询执行内存    │  │  临时文件           │ │  │
│  │  │  (Memory Cxt)  │  │  (work_mem)     │  │  (spill to disk)   │ │  │
│  │  └─────────────────┘  └─────────────────┘  └─────────────────────┘ │  │
│  └─────────────────────────────────────────────────────────────────────┘  │
│                                                                             │
└─────────────────────────────────────────────────────────────────────────────┘

1.1 内存区域划分

区域类型生命周期作用范围配置参数
共享内存服务启动到关闭所有进程共享shared_buffers
本地内存连接生命周期单个后端进程work_mem
查询内存查询执行期间单个操作work_mem
维护内存维护操作期间VACUUM/索引创建maintenance_work_mem
临时内存临时表访问会话级别temp_buffers

2. 内存上下文 (Memory Context)

2.1 核心数据结构

内存上下文是 PostgreSQL 本地内存管理的基石。定义于 src/include/nodes/memnodes.h:

c
// src/include/nodes/memnodes.h:42-57
typedef struct MemoryContextData {
    NodeTag       type;           // 上下文类型标识
    
    bool         isReset;        // 上次重置后是否分配过空间
    bool         allowInCritSection; // 关键代码段中是否允许分配
    Size         mem_allocated;  // 此上下文已分配的内存总量
    
    const MemoryContextMethods *methods;  // 虚拟函数表
    MemoryContext parent;         // 父上下文 (NULL 表示根上下文)
    MemoryContext firstchild;     // 子上下文链表头
    MemoryContext prevchild;      // 同父上下文中的前一个
    MemoryContext nextchild;      // 同父上下文中的后一个
    
    const char  *name;           // 上下文名称
    const char  *ident;          // 上下文标识符
    MemoryContextCallback *reset_cbs; // 重置/删除回调函数列表
} MemoryContextData;

2.2 内存上下文方法接口

c
// src/include/nodes/memnodes.h:58-72
typedef struct MemoryContextMethods {
    void       *(*alloc) (MemoryContext context, Size size, int flags);
    void        (*free_p) (void *pointer);
    void       *(*realloc) (void *pointer, Size size, int flags);
    void        (*reset) (MemoryContext context);       // 释放所有块,保留上下文
    void        (*delete_context) (MemoryContext context); // 彻底删除上下文
    MemoryContext (*get_chunk_context) (void *pointer);
    Size         (*get_chunk_space) (void *pointer);
    bool         (*is_empty) (MemoryContext context);
    void        (*stats) (MemoryContext context, ...);
} MemoryContextMethods;

2.3 上下文层次结构

cpp
TopMemoryContext (根上下文)

    ├── MessageContext          // 当前消息处理
    │   └── PortalContext      // Portal 执行上下文
    │       └── QueryDesc      // 查询描述符

    ├── ExecutorState (es_query_cxt)  // 查询执行上下文
    │   ├── SortState
    │   ├── HashJoinState
    │   └── AggState

    └── CurTransactionData     // 当前事务数据

2.4 AllocSet 实现详解

AllocSet 是最常用的内存上下文实现 (src/backend/utils/mmgr/aset.c):

c
// src/backend/utils/mmgr/aset.c
typedef struct AllocSetContext {
    MemoryContextData header;    // 标准内存上下文头部
    
    AllocBlock      blocks;     // 此上下文的所有内存块链表
    
    // 空闲链表数组 - 11 个,分别对应 2^3 到 2^13 字节
    MemoryChunk    *freelist[ALLOCSET_NUM_FREELISTS];
    
    uint32        initBlockSize;  // 初始块大小
    uint32        maxBlockSize;   // 最大块大小
    uint32        nextBlockSize;  // 下一个要分配的块大小
    uint32        allocChunkLimit; // 有效分块大小限制
    
    int           freeListIndex;  // 在全局空闲链表中的索引
} AllocSetContext;

// 空闲链表配置
#define ALLOC_MINBITS          3   // 最小块: 8 字节 (2^3)
#define ALLOCSET_NUM_FREELISTS 11  // 最多 8192 字节 (2^13)
#define ALLOC_CHUNK_LIMIT     (1 << ALLOCSET_NUM_FREELISTS)  // 8192

2.5 内存块结构

c
// src/backend/utils/mmgr/aset.c
typedef struct AllocBlockData {
    AllocSet   aset;        // 拥有此块的 AllocSet
    AllocBlock prev;       // 同 aset 中前一个块
    AllocBlock next;       // 同 aset 中后一个块
    char      *freeptr;    // 此块中空闲空间的起始位置
    char      *endptr;     // 此块空间的结束位置
} AllocBlockData;

2.6 分配策略图解

┌─────────────────────────────────────────────────────────────────┐
│                    AllocSet 分配策略                             │
├─────────────────────────────────────────────────────────────────┤
│                                                                 │
│  分配请求 (size)                                                │
│       │                                                         │
│       ▼                                                         │
│  ┌─────────────────────────────────────────────────────────┐   │
│  │ 大小判断: size <= 8192 ?                                 │   │
│  │                                                         │   │
│  │  ┌─────────────────────────────────────────────────┐   │   │
│  │  │ 是: 检查对应空闲链表 [freelist[idx]]            │   │   │
│  │  │     向上取整到 2 的幂: 8, 16, 32, 64, ...      │   │   │
│  │  │                                                 │   │   │
│  │  │ 空闲链表命中? ──→ 返回空闲块                    │   │   │
│  │  │     │                                           │   │   │
│  │  │     └──→ 无空闲块 ──→ 从当前块分配              │   │   │
│  │  │                     │                           │   │   │
│  │  │                     └──→ 当前块不足 ──→ 新块   │   │   │
│  │  └─────────────────────────────────────────────────┘   │   │
│  │                                                         │   │
│  │  ┌─────────────────────────────────────────────────┐   │   │
│  │  │ 否: 大块分配 (直接 malloc)                       │   │   │
│  │  │     不使用空闲链表                               │   │   │
│  │  └─────────────────────────────────────────────────┘   │   │
│  └─────────────────────────────────────────────────────────┘   │
│                                                                 │
└─────────────────────────────────────────────────────────────────┘

3. palloc/pfree 实现

3.1 palloc 函数

c
// src/backend/utils/mmgr/mcxt.c:1317-1344
void *
palloc(Size size)
{
    void       *ret;
    MemoryContext context = CurrentMemoryContext;  // 使用当前上下文
    
    Assert(MemoryContextIsValid(context));
    AssertNotInCriticalSection(context);
    
    context->isReset = false;
    
    // 通过函数指针调用上下文的 alloc 方法
    ret = context->methods->alloc(context, size, 0);
    
    Assert(ret != NULL);  // 内存不足时抛出 ERROR
    VALGRIND_MEMPOOL_ALLOC(context, ret, size);
    
    return ret;
}

3.2 palloc 变体

c
// src/include/utils/palloc.h

// 标准 palloc
void *palloc(Size size);

// 释放内存 (实际上是标记为空闲,不会真正释放)
void pfree(void *pointer);

// 重新分配
void *repalloc(void *pointer, Size size);

// 分配零初始化的内存
void *palloc0(Size size);

// 分配对齐的内存
void *palloc0fast(Size size);

// 分配数组 (自动计算元素数量)
#define pallocArray(ctx, type, n)  \
    ((type *) MemoryContextAlloc(ctx, sizeof(type) * (n)))

// 分配并零初始化数组
#define palloc0Array(ctx, type, n)  \
    ((type *) MemoryContextAllocZero(ctx, sizeof(type) * (n)))

3.3 上下文切换

c
// src/include/utils/palloc.h:123-131
static inline MemoryContext
MemoryContextSwitchTo(MemoryContext context)
{
    MemoryContext old = CurrentMemoryContext;
    CurrentMemoryContext = context;
    return old;  // 返回旧上下文,便于恢复
}

// 使用示例:
MemoryContext old_ctx = MemoryContextSwitchTo(MyQueryContext);
result = palloc(size);
/* ... */
MemoryContextSwitchTo(old_ctx);

4. 上下文生命周期管理

4.1 创建内存上下文

c
// src/backend/utils/mmgr/memutils.c
MemoryContext
AllocSetContextCreate(
    MemoryContext parent,          // 父上下文
    const char *name,              // 上下文名称
    Size      minContextSize,     // 最小上下文大小
    Size      initBlockSize,      // 初始块大小
    Size      maxBlockSize)       // 最大块大小
{
    AllocSetContext *set;
    
    // 1. 从父上下文分配上下文结构
    set = (AllocSetContext *) 
        MemoryContextAlloc(parent, sizeof(AllocSetContext));
    
    // 2. 初始化结构
    set->header.methods = &AllocSetMethods;
    set->header.parent = parent;
    set->header.name = name;
    set->blocks = NULL;
    
    // 3. 初始化空闲链表
    for (int i = 0; i < ALLOCSET_NUM_FREELISTS; i++)
        set->freelist[i] = NULL;
    
    // 4. 设置块大小参数
    set->initBlockSize = MAXALIGN(initBlockSize);
    set->maxBlockSize = MAXALIGN(maxBlockSize);
    set->nextBlockSize = set->initBlockSize;
    
    // 5. 添加到父上下文的子链表
    set->header.prevchild = NULL;
    set->header.nextchild = parent->firstchild;
    if (parent->firstchild != NULL)
        parent->firstchild->prevchild = (MemoryContext) set;
    parent->firstchild = (MemoryContext) set;
    
    return (MemoryContext) set;
}

4.2 上下文重置 vs 删除

c
// 重置上下文 - 释放所有块,保留上下文结构
void
MemoryContextReset(MemoryContext context)
{
    // 调用上下文的 reset 方法
    context->methods->reset(context);
    context->isReset = true;
}

// 删除上下文 - 递归删除所有子上下文和块
void
MemoryContextDelete(MemoryContext context)
{
    // 1. 递归删除所有子上下文
    while (context->firstchild != NULL)
        MemoryContextDelete(context->firstchild);
    
    // 2. 调用上下文的 delete_context 方法
    context->methods->delete_context(context);
}

4.3 回调机制

c
// src/include/nodes/memnodes.h:77-85
typedef void (*MemoryContextCallbackFunction) (void *arg);

typedef struct MemoryContextCallback {
    MemoryContextCallbackFunction func;  // 回调函数
    void                       *arg;    // 回调参数
    struct MemoryContextCallback *next;  // 链表下一项
} MemoryContextCallback;

// 注册回调
void
MemoryContextRegisterResetCallback(
    MemoryContext context,
    MemoryContextCallback *cb)
{
    cb->next = context->reset_cbs;
    context->reset_cbs = cb;
}

// 典型使用场景
void my_cleanup_callback(void *arg)
{
    /* 清理资源,如关闭文件句柄 */
}

MemoryContextCallback cb;
cb.func = my_cleanup_callback;
cb.arg = my_data;
MemoryContextRegisterResetCallback(ctx, &cb);

5. 共享内存 (Shared Memory)

5.1 共享内存头部结构

c
// src/include/storage/pg_shmem.h:31-44
typedef struct PGShmemHeader {
    int32       magic;          // 魔数: 679834894,用于验证
    pid_t       creatorPID;     // 创建进程的 PID
    Size        totalsize;      // 整个共享内存段大小
    Size        freeoffset;     // 第一个空闲空间的偏移量
    dsm_handle  dsm_control;   // 动态共享内存控制段 ID
    void       *index;          // ShmemIndex 哈希表指针
    dev_t       device;         // 数据目录所在设备
    ino_t       inode;         // 数据目录的 inode 号
} PGShmemHeader;

5.2 共享内存索引

所有共享内存结构通过 ShmemIndex 追踪:

c
// src/backend/storage/ipc/shmem.c
typedef struct {
    char    key[SHMEM_INDEX_KEYSIZE];  // 结构名称字符串
    Size    size;                      // 结构大小
    Size    allocated_size;            // 实际分配大小
    void   *location;                  // 起始地址
} ShmemIndexEnt;

5.3 共享内存初始化流程

cpp
CreateSharedMemoryAndSemaphores()

    ├── RequestAddinShmemSpace()      // 请求额外的 addin 空间

    ├── PGSharedMemoryCreate()
    │     │
    │     ├── 创建系统 V 共享内存段
    │     │
    │     └── 初始化 PGShmemHeader

    ├── InitShmemAccess()
    │     │
    │     └── 设置基本指针

    ├── InitShmemAllocation()
    │     │
    │     └── 初始化自旋锁用于 ShmemAlloc

    ├── InitShmemIndex()
    │     │
    │     └── 创建 shmem index 哈希表

    └── CreateOrAttachShmemStructs()

          ├── InitBufferPool()         // 初始化缓冲区缓存
          ├── InitLockTables()          // 初始化锁表
          ├── InitXactGlobals()         // 初始化事务全局变量
          ├── CreateSharedMemoryGraph() // 创建共享内存图
          └── ... 其他子系统

6. 缓冲区缓存 (Buffer Pool)

6.1 缓冲区描述符

c
// src/include/storage/buf_internals.h:244-255
typedef struct BufferDesc {
    BufferTag   tag;            // 缓冲区中页面的 ID
    int         buf_id;         // 缓冲区索引号 (0 到 N-1)
    
    // 状态组合: refcount(18位) + usage_count(4位) + flags(10位)
    pg_atomic_uint32 state;
    
    int         wait_backend_pgprocno; // 等待 pin 计数的 backend
    int         freeNext;            // 空闲链表链接
    LWLock      content_lock;        // 锁定缓冲区内容
} BufferDesc;

6.2 缓冲区标签

c
// src/include/storage/buf_internals.h:92-99
typedef struct buftag {
    Oid             spcOid;       // 表空间 OID
    Oid             dbOid;        // 数据库 OID
    RelFileNumber   relNumber;    // 关系文件号
    ForkNumber      forkNum;      // 分叉号 (main, fsm, vm, etc)
    BlockNumber     blockNum;     // 相对于关系起始的块号
} BufferTag;

6.3 缓冲区状态标志

c
// src/include/storage/buf_internals.h:59-69
#define BM_LOCKED          (1 << 0)   // 正在等待 I/O
#define BMDirty             (1 << 1)   // 页面被修改,需要写回
#define BM_VALID            (1 << 2)   // 包含有效数据
#define BM_JUST_BEEN_FREE   (1 << 3)   // 刚被释放
#define BM_TAG_VALID        (1 << 4)   // tag 有效(页面已加载)
#define BM_IO_IN_PROGRESS   (1 << 5)   // I/O 进行中

6.4 缓冲区查找流程

cpp
BufferGetBlockNumber()


hash_search_with_hash_value(tag)

    ├── 在 buf_table 哈希表中查找 BufferTag

    ├── 找到:
    │     │
    │     ├── PinBuffer() - 增加引用计数
    │     │
    │     └── 返回 BufferDesc 指针

    └── 未找到:

          ├── 选择替换缓冲区 (Clock-sweep 算法)

          ├── 如果脏页 → 写回磁盘

          ├── 从磁盘读取目标页

          └── 返回 BufferDesc 指针

6.5 BufferTable 哈希表

c
// src/backend/storage/buffer/bufmgr.c
// 缓冲区管理器使用哈希表来快速定位缓冲区

typedef struct sbufdescinfo {
    BufferDesc *bufdesc;        // 缓冲区描述符指针
    uint32      hashvalue;      // tag 的哈希值
} sbufdescinfo;

// 哈希表大小: 必须为 2 的幂
// 位置: src/include/storage/buf_internals.h:290
#define BBUFSHIFT  14
#define BBUFSIZE   (1 << BBUFSHIFT)  // 默认 16384 个缓冲区

7. 查询内存 (Query Memory)

7.1 work_mem 分配

work_mem 是 PostgreSQL 中最重要的内存参数之一,用于查询执行过程中的各种操作。

排序操作:

c
// src/backend/executor/nodeSort.c:110
TupleDesc    tupDesc;
Sort        *node;

// 每个 Sort 节点独立分配 work_mem
sortContext = AllocSetContextCreate(CurrentMemoryContext,
                                    "Sort",
                                    ALLOCSET_DEFAULT_MINSIZE,
                                    ALLOCSET_DEFAULT_INITSIZE,
                                    work_mem * 1024);  // work_mem 单位是 kB

哈希连接:

c
// src/backend/executor/nodeHash.c:3487-3497
static uint64
get_hash_memory_limit(void)
{
    double  hash_mem_multiplier = 1.0;
    
    // 使用 work_mem * hash_mem_multiplier 作为内存限制
    mem_limit = (double) work_mem * hash_mem_multiplier * 1024.0;
    return (size_t) mem_limit;
}

// 创建哈希表时分配
HashJoinTable
ExecHashTableCreate(HashJoinState *hjstate, List *hashOperators)
{
    Size    allowed = get_hash_memory_limit();
    
    // 创建哈希表上下文
    hashtable->hashCxt = AllocSetContextCreate(
        CurrentMemoryContext,
        "HashJoin",
        ALLOCSET_DEFAULT_MINSIZE,
        ALLOCSET_DEFAULT_INITSIZE,
        allowed);  // 限制为 work_mem
}

7.2 内存上下文层次

shell
TopMemoryContext

    └── EState (es_query_cxt)

          ├── HashJoinState (hashCxt)         // 哈希表
     ├── batchCxt (批次元数据)
     └── spillCxt (溢出文件)

          ├── SortState (sortcontext)         // 排序
     └── tapes[] (排序磁带)

          ├── AggState (aggcontext)           // 聚合
     └── hashTable

          └── WindowAggState (wincontext)     // 窗口函数

7.3 内存溢出到磁盘

排序溢出 (tuplesort.c):

c
// tuplesort.c 中的内存状态机
typedef enum {
    TSS_INITIAL,              // 初始状态
    TSS_BUILDRUNS,           // 构建运行(可能溢出)
    TSS_SORTEDINMEM,         // 全部在内存中排序完成
    TSS_SORTEDONTAPE,        // 溢出到磁带
    TSS_FINALMERGE           // 最终归并
} TupSortStatus;

// 内存不足检查
// tuplesort.c
#define LACKMEM(state)  ((state)->availMem < 0)

// 溢出触发条件
if (LACKMEM(state)) {
    // 将当前运行写入磁盘
    currentRun = LogicalTapeWrite(state->tapeSet, ...);
    
    // 如果运行数过多,触发全归并
    if (state->numRuns > state->maxRuns)
        return_above_materialized(state);
}

哈希连接溢出:

c
// nodeHash.c:2494-2499
while (hashtable->spaceUsedSkew > hashtable->spaceAllowedSkew) {
    // 减少倾斜批次
    ExecHashIncreaseNumBatches(hashtable);
}

if (hashtable->spaceUsed > hashtable->spaceAllowed) {
    // 溢出到磁盘
    ExecHashIncreaseNumBatches(hashtable);
}

// 增加批次时将数据写入磁盘
// 数据按哈希值分散到不同的 batch 文件

7.4 maintenance_work_mem

用于维护操作(VACUUM、CREATE INDEX 等):

c
// CREATE INDEX 时分配
// src/backend/access/nbtree/nbtsearch.c:373-432
Size sortmem = maintenance_work_mem / nparticipanttuplesorts;

tuplesort_begin_heap(tupDesc,
                     nKeys,
                     nKeys,
                     false,  // useSortAcc?
                     false,  // enforceUnique?
                     parallel,
                     sortmem,  // 使用 maintenance_work_mem
                     workPlan->randomSeed,
                     dn,
                     0);
c
// VACUUM 使用
// src/backend/commands/vacuumlazy.c
/*
 * We are willing to use at most maintenance_work_mem
 * for the dead tuple pool, but we have no estimate of
 * how many dead tuples there are.
 */
dead_tuples = (DeadTuple *) 
    palloc(min(maintMemBuffer, 
               (Size) (ntup * sizeof(DeadTuple))));

8. 临时缓冲区 (temp_buffers)

8.1 temp_buffers 特点

特性说明
默认值8MB (1024 个 8KB 缓冲区)
作用范围会话级别
影响对象仅临时表
配置时机必须在访问任何临时表之前设置

8.2 与 work_mem 的区别

维度work_memtemp_buffers
用途操作内存(排序/哈希)临时表页缓存
作用域每个操作整个会话
分配方式动态 palloc固定缓冲区池
溢出基于文件的算法LRU 淘汰
可继承否(会话级别)

9. 关键配置参数

9.1 内存相关 GUC 参数

参数默认值说明
shared_buffers128MB共享缓冲区缓存大小
work_mem4MB查询操作内存限制
maintenance_work_mem64MB维护操作内存限制
temp_buffers8MB临时表缓冲区大小
effective_cache_size4GB规划器使用的缓存估计
huge_pagestry启用大页内存
shared_memory_typemmap共享内存实现方式

9.2 推荐的内存配置公式

shell
shared_buffers = (1/4) * total_memory
work_mem = (1/4) * (total_memory - shared_buffers) / max_connections
maintenance_work_mem = (1/4) * total_memory
effective_cache_size = (3/4) * total_memory

9.3 查看内存使用

sql
-- 查看缓冲区统计
SELECT * FROM pg_stat_bgwriter;

-- 查看当前缓冲区使用
SELECT * FROM pg_buffercache;

-- 查看内存上下文
SELECT * FROM pg_memory_contexts;

-- 查看共享内存大小
SELECT * FROM pg_shared_memory_detect();

10. 核心源码文件索引

文件路径关键函数功能描述
src/include/nodes/memnodes.hMemoryContextData内存上下文结构定义
src/backend/utils/mmgr/mcxt.cpalloc/pfree内存分配实现
src/backend/utils/mmgr/aset.cAllocSetContextAllocSet 实现
src/backend/utils/mmgr/memutils.cAllocSetContextCreate上下文创建
src/include/storage/pg_shmem.hPGShmemHeader共享内存头
src/backend/storage/ipc/shmem.cShmemIndex共享内存索引
src/include/storage/buf_internals.hBufferDesc缓冲区描述符
src/backend/storage/buffer/bufmgr.cBufferGet缓冲区获取
src/backend/executor/nodeHash.cExecHashTableCreate哈希表创建
src/backend/utils/sort/tuplesort.ctuplesort_begin排序初始化
src/include/storage/buf_internals.h:290BBUFSIZE缓冲区数量宏

11. 总结

PostgreSQL 内存管理要点

  1. 内存上下文: PostgreSQL 使用树形结构的内存上下文来管理本地内存,每个上下文都有独立的块分配和空闲链表

  2. AllocSet 策略: 小于 8KB 的分配使用空闲链表优化,大于 8KB 的直接 malloc

  3. 共享内存: PostgreSQL 使用系统 V 共享内存或 mmap,包含缓冲区缓存、WAL 缓冲区、锁表等

  4. 缓冲区缓存: 使用带 Clock-sweep 算法的 LRU 淘汰策略,通过哈希表快速查找

  5. 查询内存: work_mem 控制每个操作的内存使用,超出限制时使用基于文件的溢出算法

  6. 维护内存: maintenance_work_mem 用于 VACUUM 和索引创建等维护操作

  7. 会话内存: temp_buffers 为临时表提供独立的缓冲区缓存

设计哲学

PostgreSQL 的内存管理体现了几个关键设计原则:

  • 层次化: 从共享内存到进程本地再到查询级别,层层划分
  • 隔离性: 不同操作使用独立的内存上下文,互不干扰
  • 可恢复性: 内存不足时通过溢出到磁盘保证查询完成
  • 可观测性: 提供丰富的视图和统计信息监控内存使用

本文档基于 PostgreSQL 源码分析编写,涵盖内存上下文机制、共享内存、缓冲区管理、查询内存等核心主题。