首页
学习
活动
专区
圈层
工具
发布
社区首页 >专栏 >pg_stat_statements重大BUG:内存泄露

pg_stat_statements重大BUG:内存泄露

作者头像
NickYoung
发布2026-07-09 16:39:27
发布2026-07-09 16:39:27
110
举报

分享一个pg_stat_statements内存泄露案例,尽快升级版本吧。

问题现象

一个idle的进程占用内存80G,并且在持续缓慢上涨,疑似内存泄露。

代码语言:javascript
复制
ps -eo pid,user,rss,vsz,etime,cmd --sort=-rss | grep postgres | head -3
  PID USER       RSS    VSZ    ELAPSED  CMD
2886325 postgres 80.4G   85.2G  10-17:53  postgres: postgres postgres 127.0.0.1(35458) idle
  9112 postgres  4.8G    8.1G  10-22:01  postgres: checkpointer
  9113 postgres  2.1G    6.0G  10-22:01  postgres: background writer

关键观察:

• PID 2886325 一个 backend 独占 80.4 GB,是其它进程的 16 倍以上;

• ELAPSED 字段显示该进程已存活 10 天 17 小时,是典型的常驻长连接;

• STATE 为 idle,说明问题不在执行计划,泄漏发生在某种非事务路径上;

• VSZ 与 RSS 几乎贴合,意味着泄漏的内存被全部 touch 过、是 dirty 物理页,而不是一次性 malloc 大段未使用虚地址。

问题分析

继续拿出三板斧:pmap、MemoryContext、gdb/bpftrace

pmap:

0000000001b26000 84259500 84257380 84257380 rw--- [ anon ]

从结果看80G都是匿名内存。

代码语言:javascript
复制
pmap -xx 2886325
2886325:   postgres: postgres postgres 127.0.0.1(35458) idle                                         
Address           Kbytes     RSS   Dirty Mode  Mapping
0000000000400000    9404    7032       0 r-x-- postgres
0000000000f2e000       4       4       4 r---- postgres
0000000000f2f000     112     112     100 rw--- postgres
0000000000f4b000     220      64      64 rw---   [ anon ]
0000000001aaf000     476     336     336 rw---   [ anon ]
0000000001b26000 84259500 84257380 84257380 rw---   [ anon ]
00007f1ad8a94000 1012396 1012396 1012396 rw---   [ anon ]
...省略...

MemoryContext

SELECT pg_log_backend_memory_contexts(2886325); 拿到的日志开头如下:

代码语言:javascript
复制
level: 0; TopMemoryContext: 525136 total in 11 blocks; 9736 free (17 chunks); 515400 used
level: 1; CacheMemoryContext: 1048576 total in 8 blocks; 385776 free (1 chunks); 662800 used
level: 2; relation rules: 32768 total in 7 blocks; 2216 free (1 chunks); 30552 used: pg_stat_activity
level: 2; relation rules: 16384 total in 5 blocks; 1968 free (2 chunks); 14416 used: pg_stat_statements
...   (244 个 context, 全部 index info / Cache / Portal / Timezones)
Grand total: 2406776 bytes in 244 blocks; 652168 free (233 chunks); 1754608 used

MemoryContext合计仅2.3MB,那么看起来这80GB都走的malloc申请的内存。

bpftrace

怀疑是内存泄露,大概率是代码执行中的malloc和free不匹配。

让AI写了一个bpftrace脚本,来统计malloc和free情况,脚本如下:

代码语言:javascript
复制
cat trace_leak.bt
#!/usr/bin/env bpftrace
/*
 * malloc/free 配对追踪器 
 *
 * 
 *   1. 直接输出"未释放分配"(leaked),无需人工对比 malloc vs free
 *   2. 增加实时进度提示(每次 malloc 打印 size)
 *   3. 用 @leaked_cnt / @leaked_bytes 直接统计泄漏量
 *   4. 保留原始 malloc/free 总量供参考
 *
 * 用法: sudo bpftrace -p <BACKEND_PID> trace_leak.bt
 */

BEGIN {
    printf("=== malloc/free 泄漏追踪 (优化版) ===\n");
    printf("目标 PID: %d, 阈值: >= 64KB\n", pid);
    printf("Ctrl-C 结束后直接输出泄漏调用栈.\n\n");
}

/* ===== malloc 入口:只暂存 size(不抓栈) ===== */
uprobe:/usr/lib64/libc.so.6:malloc
/arg0 >= 65536/
{
    @pending_sz[tid] = arg0;
}

/* ===== malloc 返回:在返回点抓栈(此时已退出 malloc 内部,栈更完整)===== */
uretprobe:/usr/lib64/libc.so.6:malloc
/@pending_sz[tid]/
{
    /* 关键:在 uretprobe 中抓栈,而非 uprobe 中暂存
     * 原因:malloc 内部(glibc)没有 frame pointer,uprobe 入口抓栈会丢帧
     *       uretprobe 时已返回到调用者(qtext_load_file),frame pointer 链完整 */
    $stk = ustack(perf, 10);

    /* 用指针做 key,记录 size 和调用栈 */
    @alloc_sz[retval] = @pending_sz[tid];
    @alloc_stk[retval] = $stk;

    /* 统计总 malloc */
    @total_malloc_cnt[$stk] = count();
    @total_malloc_bytes[$stk] = sum(@pending_sz[tid]);

    /* 实时打印(可注释掉减少输出) */
    printf("[MALLOC] size=%lu ptr=%p\n", @pending_sz[tid], retval);

    delete(@pending_sz[tid]);
}

/* ===== free:配对成功则从记录中移除 ===== */
uprobe:/usr/lib64/libc.so.6:free
/@alloc_sz[arg0]/
{
    /* 统计总 free */
    @total_free_cnt[@alloc_stk[arg0]] = count();
    @total_free_bytes[@alloc_stk[arg0]] = sum(@alloc_sz[arg0]);

    printf("[FREE]   size=%lu ptr=%p\n", @alloc_sz[arg0], arg0);

    /* 配对成功,从未释放记录中移除 */
    delete(@alloc_sz[arg0]);
    delete(@alloc_stk[arg0]);
}

/* ===== 结束时输出报告 ===== */
END {
    printf("\n");
    printf("╔══════════════════════════════════════════════╗\n");
    printf("║          内存泄漏分析报告                    ║\n");
    printf("╚══════════════════════════════════════════════╝\n");

    /*
     * 核心:遍历 @alloc_sz 中仍然存在的 key
     * 这些就是"malloc 了但从未 free"的指针 = 泄漏
     */
    printf("\n===== 1. 未释放的分配(泄漏) =====\n");
    printf("以下指针 malloc 后从未被 free:\n\n");
    print(@alloc_sz);

    printf("\n===== 2. 未释放分配的调用栈 =====\n");
    printf("泄漏指针对应的 malloc 调用栈:\n\n");
    print(@alloc_stk);

    printf("\n===== 3. malloc 总计(按调用栈聚合)=====\n");
    print(@total_malloc_cnt);
    print(@total_malloc_bytes);

    printf("\n===== 4. free 总计(按调用栈聚合)=====\n");
    print(@total_free_cnt);
    print(@total_free_bytes);

    printf("\n===== 判定方法 =====\n");
    printf("• 第1节中仍存在的 ptr → 泄漏\n");
    printf("• 第2节中对应的调用栈 → 泄漏位置\n");
    printf("• 第3节 malloc_cnt - 第4节 free_cnt = 泄漏次数\n");
    printf("════════════════════════════════════════════════\n");

    clear(@alloc_sz);
    clear(@alloc_stk);
    clear(@pending_sz);
    clear(@total_malloc_cnt);
    clear(@total_malloc_bytes);
    clear(@total_free_cnt);
    clear(@total_free_bytes);
}

执行sudo bpftrace -p 2886325 trace_leak.bt

代码语言:javascript
复制
sudo bpftrace -p 2886325 trace_leak.bt
Attaching 5 probes...
=== malloc/free 泄漏追踪 (优化版) ===
目标 PID: 2888525, 阈值: >= 64KB
Ctrl-C 结束后直接输出泄漏调用栈.
...省略...

===== 2. 未释放分配的调用栈 =====
泄漏指针对应的 malloc 调用栈:

@alloc_stk[300048528]: 
        7f353370b0b7 qtext_load_file+302 (/data/postgres/postgres-REL_18_3/lib/pg_stat_statements.so)
        7f3533709bb0 pg_stat_statements_internal+1283 (/data/postgres/postgres-REL_18_3/lib/pg_stat_statements.so)
        7f353370951b pg_stat_statements_1_12+52 (/data/postgres/postgres-REL_18_3/lib/pg_stat_statements.so)
        6b84c8 ExecMakeTableFunctionResult+742 (/data/postgres/postgres-REL_18_3/bin/postgres)
        6d1d4e FunctionNext+178 (/data/postgres/postgres-REL_18_3/bin/postgres)
        6b9c1a ExecScanFetch+611 (/data/postgres/postgres-REL_18_3/bin/postgres)
        6b9c81 ExecScanExtended+101 (/data/postgres/postgres-REL_18_3/bin/postgres)
        6b9ded ExecScan+104 (/data/postgres/postgres-REL_18_3/bin/postgres)
        6d20df ExecFunctionScan+42 (/data/postgres/postgres-REL_18_3/bin/postgres)
        6b5b21 ExecProcNodeFirst+77 (/data/postgres/postgres-REL_18_3/bin/postgres)
@alloc_stk[300211360]: 
        7f353370b0b7 qtext_load_file+302 (/data/postgres/postgres-REL_18_3/lib/pg_stat_statements.so)
        7f3533709bb0 pg_stat_statements_internal+1283 (/data/postgres/postgres-REL_18_3/lib/pg_stat_statements.so)
        7f353370951b pg_stat_statements_1_12+52 (/data/postgres/postgres-REL_18_3/lib/pg_stat_statements.so)
        6b84c8 ExecMakeTableFunctionResult+742 (/data/postgres/postgres-REL_18_3/bin/postgres)
        6d1d4e FunctionNext+178 (/data/postgres/postgres-REL_18_3/bin/postgres)
        6b9c1a ExecScanFetch+611 (/data/postgres/postgres-REL_18_3/bin/postgres)
        6b9c81 ExecScanExtended+101 (/data/postgres/postgres-REL_18_3/bin/postgres)
        6b9ded ExecScan+104 (/data/postgres/postgres-REL_18_3/bin/postgres)
        6d20df ExecFunctionScan+42 (/data/postgres/postgres-REL_18_3/bin/postgres)
        6b5b21 ExecProcNodeFirst+77 (/data/postgres/postgres-REL_18_3/bin/postgres)
@alloc_stk[300374192]: 
        7f353370b0b7 qtext_load_file+302 (/data/postgres/postgres-REL_18_3/lib/pg_stat_statements.so)
        7f3533709bb0 pg_stat_statements_internal+1283 (/data/postgres/postgres-REL_18_3/lib/pg_stat_statements.so)
        7f353370951b pg_stat_statements_1_12+52 (/data/postgres/postgres-REL_18_3/lib/pg_stat_statements.so)
        6b84c8 ExecMakeTableFunctionResult+742 (/data/postgres/postgres-REL_18_3/bin/postgres)
        6d1d4e FunctionNext+178 (/data/postgres/postgres-REL_18_3/bin/postgres)
        6b9c1a ExecScanFetch+611 (/data/postgres/postgres-REL_18_3/bin/postgres)
        6b9c81 ExecScanExtended+101 (/data/postgres/postgres-REL_18_3/bin/postgres)
        6b9ded ExecScan+104 (/data/postgres/postgres-REL_18_3/bin/postgres)
        6d20df ExecFunctionScan+42 (/data/postgres/postgres-REL_18_3/bin/postgres)
        6b5b21 ExecProcNodeFirst+77 (/data/postgres/postgres-REL_18_3/bin/postgres)
@alloc_stk[300537024]: 
        7f353370b0b7 qtext_load_file+302 (/data/postgres/postgres-REL_18_3/lib/pg_stat_statements.so)
        7f3533709bb0 pg_stat_statements_internal+1283 (/data/postgres/postgres-REL_18_3/lib/pg_stat_statements.so)
        7f353370951b pg_stat_statements_1_12+52 (/data/postgres/postgres-REL_18_3/lib/pg_stat_statements.so)
        6b84c8 ExecMakeTableFunctionResult+742 (/data/postgres/postgres-REL_18_3/bin/postgres)
        6d1d4e FunctionNext+178 (/data/postgres/postgres-REL_18_3/bin/postgres)
        6b9c1a ExecScanFetch+611 (/data/postgres/postgres-REL_18_3/bin/postgres)
        6b9c81 ExecScanExtended+101 (/data/postgres/postgres-REL_18_3/bin/postgres)
        6b9ded ExecScan+104 (/data/postgres/postgres-REL_18_3/bin/postgres)
        6d20df ExecFunctionScan+42 (/data/postgres/postgres-REL_18_3/bin/postgres)
        6b5b21 ExecProcNodeFirst+77 (/data/postgres/postgres-REL_18_3/bin/postgres)
@alloc_stk[300699856]: 
        7f353370b0b7 qtext_load_file+302 (/data/postgres/postgres-REL_18_3/lib/pg_stat_statements.so)
        7f3533709bb0 pg_stat_statements_internal+1283 (/data/postgres/postgres-REL_18_3/lib/pg_stat_statements.so)
        7f353370951b pg_stat_statements_1_12+52 (/data/postgres/postgres-REL_18_3/lib/pg_stat_statements.so)
        6b84c8 ExecMakeTableFunctionResult+742 (/data/postgres/postgres-REL_18_3/bin/postgres)
        6d1d4e FunctionNext+178 (/data/postgres/postgres-REL_18_3/bin/postgres)
        6b9c1a ExecScanFetch+611 (/data/postgres/postgres-REL_18_3/bin/postgres)
        6b9c81 ExecScanExtended+101 (/data/postgres/postgres-REL_18_3/bin/postgres)
        6b9ded ExecScan+104 (/data/postgres/postgres-REL_18_3/bin/postgres)
        6d20df ExecFunctionScan+42 (/data/postgres/postgres-REL_18_3/bin/postgres)
        6b5b21 ExecProcNodeFirst+77 (/data/postgres/postgres-REL_18_3/bin/postgres)

可以看到malloc但未free的栈为:

代码语言:javascript
复制
        7f353370b0b7 qtext_load_file+302 (/data/postgres/postgres-REL_18_3/lib/pg_stat_statements.so)
        7f3533709bb0 pg_stat_statements_internal+1283 (/data/postgres/postgres-REL_18_3/lib/pg_stat_statements.so)
        7f353370951b pg_stat_statements_1_12+52 (/data/postgres/postgres-REL_18_3/lib/pg_stat_statements.so)
        6b84c8 ExecMakeTableFunctionResult+742 (/data/postgres/postgres-REL_18_3/bin/postgres)
        6d1d4e FunctionNext+178 (/data/postgres/postgres-REL_18_3/bin/postgres)
        6b9c1a ExecScanFetch+611 (/data/postgres/postgres-REL_18_3/bin/postgres)
        6b9c81 ExecScanExtended+101 (/data/postgres/postgres-REL_18_3/bin/postgres)
        6b9ded ExecScan+104 (/data/postgres/postgres-REL_18_3/bin/postgres)
        6d20df ExecFunctionScan+42 (/data/postgres/postgres-REL_18_3/bin/postgres)
        6b5b21 ExecProcNodeFirst+77 (/data/postgres/postgres-REL_18_3/bin/postgres)

从栈可以看出来是pg_stat_statements的问题,疑点在qtext_load_file+302这个偏移量,可以使用addr2line转换为源码行号。

代码语言:javascript
复制
PGSS_SO=/data/postgres/postgres-REL_18_3/lib/pg_stat_statements.so

# qtext_load_file 的起始地址
FUNC_OFF=$(nm $PGSS_SO | awk '/ qtext_load_file$/{print $1}')
echo "qtext_load_file 起始地址: 0x$FUNC_OFF"

# +302 = +0x12E
TARGET=$(printf "0x%x" $((0x$FUNC_OFF + 302)))
echo "目标地址: $TARGET"

# 翻译成源码行
addr2line -e $PGSS_SO -f -C $TARGET
qtext_load_file 起始地址: 0x0000000000004f89
目标地址: 0x50b7
qtext_load_file
/data/postgres/postgres-REL_18_3/contrib/pg_stat_statements/pg_stat_statements.c:2338

定位到/data/postgres/postgres-REL_18_3/contrib/pg_stat_statements/pg_stat_statements.c:2338为函数qtext_load_file:

代码语言:javascript
复制
static char *
qtext_load_file(Size *buffer_size)
{
    char       *buf;
    int         fd;
    struct stat stat;

    fd = OpenTransientFile(PGSS_TEXT_FILE, O_RDONLY | PG_BINARY);
    if (fd < 0)
    {
        if (errno != ENOENT)
            ereport(LOG, ...);
        return NULL;
    }

    if (fstat(fd, &stat))
    {
        ereport(LOG, ...);
        CloseTransientFile(fd);
        return NULL;
    }

    /* ★ 关键点 1:用 malloc 分配 buffer */
    if (stat.st_size <= MaxAllocHugeSize)
        buf = (char *) malloc(stat.st_size);    // ←2338行,泄漏源头
    else
        buf = NULL;
    if (buf == NULL)
    {
        ereport(LOG, ...);
        CloseTransientFile(fd);
        return NULL;
    }

    /* 读取文件到 buf */
    errno = 0;
    if (read(fd, buf, stat.st_size) != stat.st_size)
    {
        if (errno)
            ereport(LOG, ...);
        free(buf);              // ← 只有读取失败时有 free
        CloseTransientFile(fd);
        return NULL;
    }

    CloseTransientFile(fd);

    *buffer_size = stat.st_size;
    return buf;                 // ★ 正常路径:返回 buf 给调用者负责释放
}

再看调用着pg_stat_statements_internal:

代码语言:javascript
复制
static void
pg_stat_statements_internal(FunctionCallInfo fcinfo, ...)
{
    char       *qbuffer = NULL;
    Size        qbuffer_size = 0;
    ...

    if (showtext)
    {
        if (n_writers == 0)
            qbuffer = qtext_load_file(&qbuffer_size);  // ★ 第一次调用
    }

    LWLockAcquire(pgss->lock, LW_SHARED);

    if (showtext)
    {
        if (qbuffer == NULL || pgss->extent != extent || pgss->gc_count != gc_count)
        {
            if (qbuffer)
                free(qbuffer);
            qbuffer = qtext_load_file(&qbuffer_size);  // ★ 第二次调用(重新加载)
        }
    }

    /* 遍历哈希表 ... */
    while ((entry = hash_seq_search(&hash_seq)) != NULL)
    {
        if (showtext)
        {
            char *qstr = qtext_fetch(entry->query_offset,
                                     entry->query_len,
                                     qbuffer,
                                     qbuffer_size);
            if (qstr)
            {
                char *enc;
                enc = pg_any_to_server(qstr,           // ★ 关键点 2:编码转换
                                       entry->query_len,
                                       entry->encoding);
                values[i++] = CStringGetTextDatum(enc); // ★ 关键点 3
                if (enc != qstr)
                    pfree(enc);
            }
        }
        ...
        tuplestore_putvalues(tupstore, tupdesc, values, nulls);
    }

    LWLockRelease(pgss->lock);

    if (qbuffer)
        free(qbuffer);       // ★ 正常路径:函数末尾释放 qbuffer

    tuplestore_donestoring(tupstore);
}

从bpftrace结果看,这里肯定没有进入正常free路径。

同时发现进程一直在报错:

代码语言:javascript
复制
ERROR:  invalid byte sequence for encoding "UTF8": 0x00

因此泄露的路径为:

代码语言:javascript
复制
qtext_load_file() 用 malloc 分配 buf,读取文件内容(含 NUL 字节)
    ↓
返回 buf 指针赋给 qbuffer
    ↓
进入 while 循环遍历哈希表
    ↓
qtext_fetch() 从 qbuffer 中提取某条 query text(qstr)
    ↓
pg_any_to_server(qstr, entry->query_len, entry->encoding)
    ↓
内部调用 pg_verify_mbstr_len() 校验编码合法性
    ↓
遇到 0x00 字节 → 触发 ereport(ERROR):
    "invalid byte sequence for encoding "UTF8": 0x00"
    ↓
ereport(ERROR) 内部调用 longjmp() → 直接跳回错误处理器
    ↓
★★★ 关键:longjmp 跳过了函数末尾的 free(qbuffer) ★★★
    ↓
qbuffer 指向的 malloc 内存永远无法被释放 → 泄漏!

这很明确是一个BUG,并且我的dba agent给出了BUG详情:

Avoid memory leak on error while parsing pg_stat_statements dump file

By using palloc() instead of raw malloc().

Reported-by: Gaurav Singh gaurav.singh@yugabyte.comReviewed-by: Lukas Fittl lukas@fittl.comReviewed-by: Daniel Gustafsson daniel@yesql.seDiscussion: https://www.postgresql.org/message-id/CAEcQ1bYR9s4eQLFDjzzJHU8fj-MTbmRpW-9J-r2gsCn+HEsynw@mail.gmail.com Backpatch-through: 14

Commit Hash

3c74cb5762db6373187c3cf83f1b955e88773e33

标题

Avoid memory leak on error while parsing pg_stat_statements dump file

作者

Heikki Linnakangasheikki.linnakangas@iki.fi

日期

2026-03-27

Reporter

Gaurav Singh (Yugabyte)

Reviewers

Lukas Fittl, Daniel Gustafsson

回合分支

Backpatch-through: 14(即 14/15/16/17/18/master 都已修复)

讨论邮件

https://www.postgresql.org/message-id/CAEcQ1bYR9s4eQLFDjzzJHU8fj-MTbmRpW-9J-r2gsCn+HEsynw@mail.gmail.com

Web 链接

https://github.com/postgres/postgres/commit/3c74cb5762db

修复方案

patch Diff 完整内容(共 6 处修改、净 +8 / -7) 修改点 1:pgss_shmem_shutdown 正常路径(行 805)

代码语言:javascript
复制
diff

- free(qbuffer);
+ pfree(qbuffer);
  qbuffer = NULL;

修改点 2:pgss_shmem_shutdown 错误路径 error: label(行 829)

代码语言:javascript
复制
diff
- free(qbuffer);
+ if (qbuffer)
+  pfree(qbuffer);
  if (file)
   FreeFile(file);

修改点 3:pg_stat_statements_internal 重读文件路径(行 1825)

代码语言:javascript
复制
diff
-   free(qbuffer);
+   if (qbuffer)
+    pfree(qbuffer);
    qbuffer = qtext_load_file(&qbuffer_size);

修改点 4:pg_stat_statements_internal 函数末尾正常清理(行 2046)⭐ 本次内存泄漏的关键路径

代码语言:javascript
复制
diff
LWLockRelease(pgss->lock);

- free(qbuffer);
+ if (qbuffer)
+  pfree(qbuffer);

关键原理:把 qbuffer 从 malloc 切到 palloc_extended(见修改点 5),buffer 直接挂在 CurrentMemoryContext 上。一旦 pg_any_to_server() 在循环内 throw ERROR 22P05,AbortTransaction → MemoryContextDelete 会自动回收 qbuffer,不再依赖被 longjmp 跳过的 free(qbuffer)——根因彻底消除。

修改点 5:qtext_load_file 改 malloc 为 palloc_extended(行 2333、2378) diff

代码语言:javascript
复制
/*
- * Read the external query text file into a malloc'd buffer.
+ * Read the external query text file into a palloc'd buffer.
  *
  * Returns NULL (without throwing an error) if unable to read, eg
  * file not there or insufficient memory.
@@ qtext_load_file ...
  /* Allocate buffer; beware that off_t might be wider than size_t */
  if (stat.st_size <= MaxAllocHugeSize)
-  buf = (char *) malloc(stat.st_size);
+  buf = (char *) palloc_extended(stat.st_size, MCXT_ALLOC_HUGE | MCXT_ALLOC_NO_OOM);
  else
   buf = NULL;

用 MCXT_ALLOC_HUGE | MCXT_ALLOC_NO_OOM 完全保留原 malloc 的语义:允许 >1GB 的超大分配 + OOM 时返回 NULL 而非 throw。

修改点 6:qtext_load_file 内部 read 失败路径(行 2417)

代码语言:javascript
复制
diff
ereport(LOG, ...);
-   free(buf);
+   pfree(buf);
    CloseTransientFile(fd);
    return NULL;

修改点 7:gc_qtexts 正常路径(行 2625)

代码语言:javascript
复制
diff
- free(qbuffer);
+ pfree(qbuffer);

修改点 8:gc_qtexts 失败 label gc_fail:(行 2642) diff

代码语言:javascript
复制
- free(qbuffer);
+ if (qbuffer)
+  pfree(qbuffer);

赶紧升级吧!!!

大版本

❌未修复(最后一个含 bug 的版本)

✅已修复(包含此修复的最早小版本)

14.x

14.22 及之前所有版本

14.23

15.x

15.17 及之前所有版本

15.18

16.x

16.13 及之前所有版本

16.14

17.x

17.9 及之前所有版本

17.10

18.x

18.3 及之前所有版本

18.4

13.x 及更早

全部版本

❌永不会修复(13 已 EOL,且 backpatch 只到 14)

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2026-05-18,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 PostgreSQL运维之道 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 问题现象
  • 问题分析
    • pmap:
    • MemoryContext
    • bpftrace
  • 修复方案
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档