From: Alvaro Herrera Date: Mon, 8 Nov 2010 21:35:42 +0000 (-0300) Subject: Fix permanent memory leak in autovacuum launcher X-Git-Tag: REL9_1_ALPHA3~202 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=854ae8c3a6bab2053f8bdbc453787be878ce8c81;p=postgresql Fix permanent memory leak in autovacuum launcher get_database_list was uselessly allocating its output data, along some created along the way, in a permanent memory context. This didn't matter when autovacuum was a single, short-lived process, but now that the launcher is permanent, it shows up as a permanent leak. To fix, make get_database list allocate its output data in the caller's context, which is in charge of freeing it when appropriate; and the memory leaked by heap_beginscan et al is allocated in a throwaway transaction context. --- diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c index e7176448a0..a617b882a3 100644 --- a/src/backend/postmaster/autovacuum.c +++ b/src/backend/postmaster/autovacuum.c @@ -1754,6 +1754,9 @@ autovac_balance_cost(void) * get_database_list * Return a list of all databases found in pg_database. * + * The list and associated data is allocated in the caller's memory context, + * which is in charge of ensuring that it's properly cleaned up afterwards. + * * Note: this is the only function in which the autovacuum launcher uses a * transaction. Although we aren't attached to any particular database and * therefore can't access most catalogs, we do have enough infrastructure @@ -1766,6 +1769,10 @@ get_database_list(void) Relation rel; HeapScanDesc scan; HeapTuple tup; + MemoryContext resultcxt; + + /* This is the context that we will allocate our output data in */ + resultcxt = CurrentMemoryContext; /* * Start a transaction so we can access pg_database, and get a snapshot. @@ -1777,9 +1784,6 @@ get_database_list(void) StartTransactionCommand(); (void) GetTransactionSnapshot(); - /* Allocate our results in AutovacMemCxt, not transaction context */ - MemoryContextSwitchTo(AutovacMemCxt); - rel = heap_open(DatabaseRelationId, AccessShareLock); scan = heap_beginscan(rel, SnapshotNow, 0, NULL); @@ -1787,6 +1791,15 @@ get_database_list(void) { Form_pg_database pgdatabase = (Form_pg_database) GETSTRUCT(tup); avw_dbase *avdb; + MemoryContext oldcxt; + + /* + * Allocate our results in the caller's context, not the transaction's. + * We do this inside the loop, and restore the original context at the + * end, so that leaky things like heap_getnext() are not called in a + * potentially long-lived context. + */ + oldcxt = MemoryContextSwitchTo(resultcxt); avdb = (avw_dbase *) palloc(sizeof(avw_dbase)); @@ -1797,6 +1810,7 @@ get_database_list(void) avdb->adw_entry = NULL; dblist = lappend(dblist, avdb); + MemoryContextSwitchTo(oldcxt); } heap_endscan(scan);