public inbox for [email protected]  
help / color / mirror / Atom feed
From: Baji Shaik <[email protected]>
To: [email protected]
Cc: [email protected]
Subject: [PATCH] Fix memory leak in pgstat_progress_parallel_incr_param()
Date: Fri, 5 Jun 2026 12:44:24 -0500
Message-ID: <CA+fm-RMopta1Dmq8udiU5sp+zwTvhUf4+xfbr3rZDfczH+p-xw@mail.gmail.com> (raw)

Hi,

While running parallel vacuum with track_cost_delay_timing=on, I
noticed memory in the parallel worker process keeps growing
proportionally to vacuum runtime, and is never reclaimed until the
worker exits.

I think pgstat_progress_parallel_incr_param() (backend_progress.c)
leaks memory on every call from a parallel worker.

The suspected block:

    static StringInfoData progress_message;
    initStringInfo(&progress_message);                /* palloc -> A   */
    pq_beginmessage(&progress_message, PqMsg_Progress);
    /* pq_beginmessage internally calls initStringInfo again ->
       palloc -> B, A is orphaned                                       */
    pq_sendint32(&progress_message, index);
    pq_sendint64(&progress_message, incr);
    pq_endmessage(&progress_message);                 /* pfree(B), A leaked
*/

So one palloc(~1 kB) leaks per call, into the per-worker context.

This is an oversight of f1889729dd3 ("Add new parallel message type
to progress reporting"); track_cost_delay_timing just makes it more
visible.  With that GUC enabled, a long-running parallel vacuum leaks
megabytes per worker (~232 MB observed in a 43-min vacuum at default
settings on a 15M-row, 30-index workload).

The proposed fix is in the attached patch which does a one-time init of the
static
buffer, then pq_beginmessage_reuse() / pq_endmessage_reuse() so the
buffer is allocated once and reused.

All 245 regression tests pass.

Thanks,
Baji Shaik.


Attachments:

  [application/octet-stream] 0001-Fix-memory-leak-in-pgstat_progress_parallel_incr_par.patch (2.4K, 3-0001-Fix-memory-leak-in-pgstat_progress_parallel_incr_par.patch)
  download | inline diff:
From 590712b4fea381a82cfaa9aa17bbe0f07ca0c16a Mon Sep 17 00:00:00 2001
From: Baji Shaik <[email protected]>
Date: Fri, 5 Jun 2026 12:40:18 -0500
Subject: [PATCH] Fix memory leak in pgstat_progress_parallel_incr_param()

When called from a parallel worker, pgstat_progress_parallel_incr_param()
calls initStringInfo() on a static StringInfoData and then immediately
calls pq_beginmessage(), which calls initStringInfo() again.  The second
call overwrites buf->data with a freshly palloc'd buffer, orphaning the
first one.  pq_endmessage() then frees only the second buffer, so each
call leaks ~1 kB into the per-worker memory context.

The leak is negligible by default, but with track_cost_delay_timing
enabled the parallel cost-delay reporting path fires once per second per
worker, so a long-running parallel vacuum leaks megabytes per worker.

Fix by initializing the static buffer once per process and using
pq_beginmessage_reuse()/pq_endmessage_reuse(), so the buffer is allocated
once and reused.

This is an oversight of f1889729dd3 ("Add new parallel message type to
progress reporting"); track_cost_delay_timing just makes it more visible.

Author: Baji Shaik <[email protected]>
---
 src/backend/utils/activity/backend_progress.c | 20 ++++++++++++++-----
 1 file changed, 15 insertions(+), 5 deletions(-)

diff --git a/src/backend/utils/activity/backend_progress.c b/src/backend/utils/activity/backend_progress.c
index b0359771de5..0483741a80e 100644
--- a/src/backend/utils/activity/backend_progress.c
+++ b/src/backend/utils/activity/backend_progress.c
@@ -99,13 +99,23 @@ pgstat_progress_parallel_incr_param(int index, int64 incr)
 	if (IsParallelWorker())
 	{
 		static StringInfoData progress_message;
-
-		initStringInfo(&progress_message);
-
-		pq_beginmessage(&progress_message, PqMsg_Progress);
+		static bool progress_message_initialized = false;
+
+		/*
+		 * Initialize the message buffer once per process; pq_beginmessage_reuse()
+		 * and pq_endmessage_reuse() reset and reuse it on each call to avoid
+		 * palloc overhead.
+		 */
+		if (!progress_message_initialized)
+		{
+			initStringInfo(&progress_message);
+			progress_message_initialized = true;
+		}
+
+		pq_beginmessage_reuse(&progress_message, PqMsg_Progress);
 		pq_sendint32(&progress_message, index);
 		pq_sendint64(&progress_message, incr);
-		pq_endmessage(&progress_message);
+		pq_endmessage_reuse(&progress_message);
 	}
 	else
 		pgstat_progress_incr_param(index, incr);
-- 
2.50.1 (Apple Git-155)



view thread (6+ messages)  latest in thread

reply

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Reply to all the recipients using the --to and --cc options:
  reply via email

  To: [email protected]
  Cc: [email protected], [email protected], [email protected]
  Subject: Re: [PATCH] Fix memory leak in pgstat_progress_parallel_incr_param()
  In-Reply-To: <CA+fm-RMopta1Dmq8udiU5sp+zwTvhUf4+xfbr3rZDfczH+p-xw@mail.gmail.com>

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

This inbox is served by agora; see mirroring instructions
for how to clone and mirror all data and code used for this inbox