当前位置:首页 > 技术 > 正文内容

PostgreSQL内存管理详解

访客 技术 2026年7月16日 1

1. 概述

本文深入探讨PostgreSQL(简称PG)的内存管理机制,包括内存分配方式、分配流程以及各层级之间的关系。此外,文章还介绍了通过函数指针实现动态分配策略的方式,并重点分析了进程本地内存管理和多进程共享内存管理。

2. 内存管理原理

操作系统通常使用链表将相同大小的缓冲区连接起来以管理小块内存。类似地,PG定义了11个不同大小的空闲列表(freelist),用于管理不同尺寸的内存块。例如:
#define ALLOC_MINBITS       3   /* 最小内存块为8字节 */
#define ALLOCSET_NUM_FREELISTS  11 /* freelist数量 */
#define ALLOC_CHUNK_LIMIT   (1 << (ALLOCSET_NUM_FREELISTS-1+ALLOC_MINBITS)) /* 最大固定尺寸内存块 */

3. 内存管理代码结构

3.1 整体设计

PG的内存管理采用两级结构:`MemoryContextData`记录和管理内存树的信息,而`AllocSetContext`负责具体的内存分配与管理。

3.2 MemoryContextData结构

以下是`MemoryContextData`的定义,其中包含父节点、子节点以及方法指针表等信息:
typedef struct MemoryContextData {
    NodeTag type;               /* 上下文类型 */
    bool isReset;               /* 是否重置 */
    bool allowInCritSection;   /* 是否允许在关键段内分配 */
    const MemoryContextMethods *methods; /* 方法指针表 */
    MemoryContext parent;       /* 父节点 */
    MemoryContext firstchild;  /* 子节点链表头 */
    MemoryContext prevchild;   /* 前一个兄弟节点 */
    MemoryContext nextchild;   /* 后一个兄弟节点 */
    const char *name;          /* 名称 */
    const char *ident;         /* 标识符 */
    MemoryContextCallback *reset_cbs; /* 回调列表 */
} MemoryContextData;

3.3 MemoryContextMethods定义

`MemoryContextMethods`是一个方法指针表,定义了各种内存操作接口:
typedef struct MemoryContextMethods {
    void *(*alloc)(MemoryContext context, Size size); /* 分配 */
    void (*free_p)(MemoryContext context, void *pointer); /* 释放 */
    void *(*realloc)(MemoryContext context, void *pointer, Size size); /* 重新分配 */
    void (*reset)(MemoryContext context); /* 重置 */
    void (*delete_context)(MemoryContext context); /* 删除上下文 */
    Size (*get_chunk_space)(MemoryContext context, void *pointer); /* 获取块大小 */
    bool (*is_empty)(MemoryContext context); /* 是否为空 */
    void (*stats)(MemoryContext context,
                  MemoryStatsPrintFunc printfunc, void *passthru,
                  MemoryContextCounters *totals); /* 统计 */
#ifdef MEMORY_CONTEXT_CHECKING
    void (*check)(MemoryContext context); /* 检查 */
#endif
} MemoryContextMethods;

3.4 AllocSetContext结构

`AllocSetContext`负责实际的内存分配管理:
typedef struct AllocSetContext {
    MemoryContextData header; /* 标准内存上下文字段 */
    AllocBlock blocks;        /* 内存块链表头 */
    AllocChunk freelist[ALLOCSET_NUM_FREELISTS]; /* 空闲块链表 */
    Size initBlockSize;       /* 初始块大小 */
    Size maxBlockSize;        /* 最大块大小 */
    Size nextBlockSize;       /* 下一块大小 */
    Size allocChunkLimit;    /* 块大小限制 */
    AllocBlock keeper;        /* 保留块 */
    int freeListIndex;        /* 空闲列表索引 */
} AllocSetContext;

4. 内存分配与释放逻辑

当需要分配内存时,PG不会直接调用`malloc`,而是先通过`malloc`申请一大块内存,再从中切割出合适的内存片返回给用户。释放内存时,也不会直接归还给操作系统,而是通过空闲列表(freelist)保存这些碎片供后续使用。 如果请求的内存大小超过`allocChunkLimit`,则会直接通过`malloc`分配整块内存并返回;否则,PG会根据请求大小计算对应的空闲列表索引,并从该列表中寻找合适的内存块。

5. 内存上下文层次结构

程序启动时会初始化顶层内存上下文`TopMemoryContext`,其层次结构如下:
  • `TopMemoryContext`:最顶层的内存上下文。
  • `CacheMemoryContext`:持久存储RelCache、CatCache等模块的数据。
  • `MessageContext`:存储与当前命令相关的数据。
  • `TopTransactionContext`:事务级别的内存上下文。
  • `CurTransactionContext`:当前事务使用的内存上下文。
  • `ErrorContext`:错误恢复过程中使用的内存上下文。

6. 共享内存区域

共享内存区域主要包括以下部分:
  • `Shared buffer pool`:存储表和索引页面。
  • `WAL buffer`:事务日志写入前的缓存区域。
  • `Commit log buffer`:保存事务状态信息。

7. 查看内存上下文

从PG14开始,可以通过`pg_log_backend_memory_contexts`函数查看内存上下文的使用情况。例如:
SELECT pg_log_backend_memory_contexts(pid);
标签: PostgreSQL

相关文章

Linux crontab 详解

1) crontab 是什么cron 是 Linux 的定时任务守护进程;crontab 是用来编辑/查看“按时间周期执行命令”的表(cron table)。常见两类:用户 crontab:每个用户一份(crontab -e 编辑)系统级 crontab / cron.d:可指定执行用户(/etc/crontab、/etc/cron.d/*)2) crontab 时间...

富文本里可以允许的 HTML 属性

一、所有标签默认允许的安全属性(极少)class        (可选)id           (通常建议禁用)title️ 注意:id 容易被滥用做锚点注入,很多系统直接禁用class 允许的话最好只允许固定前缀(如 editor-*)二、a 标签允许属性<a href="" t...

Mac 安装 Node.js 指南

方法一:通过官网安装包(最简单,适合初学者)如果你只是想快速安装并开始使用,这是最直接的方法。访问 Node.js 官网。页面会显示两个版本:LTS (Recommended For Most Users):长期支持版,最稳定。建议选这个。Current:最新特性版,包含最新功能但可能不够稳定。下载 .pkg 安装包并运行。按照安装向导点击“下一步”即可完成。方法二:使用 Homebrew 安装(...

Dom\HTML_NO_DEFAULT_NS 的副作用:自动加闭合标签

在使用Dom\HTMLDocument时,Dom\HTML_NO_DEFAULT_NS 将禁止在解析过程中设置元素的命名空间, 此设置是为了与DOMDocument向后兼容而存在的。当使用它时,已知的一个副作用就是:自动加闭合标签例如 </img> 为什么会这样?当你使用:Dom\HTML_NO_DEFAULT_NS文档会变成 无命名空间模式,此时内部更接近 XML...

Laravel 事件和监听器创建

在 Laravel 中,使用 Artisan 命令创建 Events(事件) 和 Listeners(监听器) 是非常高效的。你可以通过以下几种方式来实现:1. 手动创建单个 Event如果你只想创建一个事件类,可以使用 make:event 命令:Bashphp artisan make:event UserRegistered执行后,文件将生成在 app/Even...

自定义域名解析神器 dnsmasq

什么是 dnsmasq?dnsmasq 是一个轻量级、功能强大的网络服务工具,专为小型和中等规模网络设计。它是一个综合的网络基础设施解决方案[1]。dnsmasq 能做什么?功能说明应用场景DNS 转发与缓存将 DNS 查询转发到上游服务器(ISP、Google DNS 等),并在本地缓存结果加快 DNS 查询速度,减少外部 DNS 流量本地 DNS解析本地网络设备的主机名,无需编辑&n...

发表评论

访客

◎欢迎参与讨论,请在这里发表您的看法和观点。