From ac03d99956097ba679d96c9b407facf733277360 Mon Sep 17 00:00:00 2001
From: David Geier <geidav.pg@gmail.com>
Date: Fri, 18 Sep 2026 12:17:11 +0200
Subject: [PATCH v3 2/8] Allocate RelationData structs in a dedicated slab
 context

The power-of-two size classes of aset mean that reductions in the size
of RelationData often yield no actual memory savings, as the allocation
is rounded up to the next size class anyway.

RelationData objects are fixed-size and numerous, so they are a good fit
for a slab allocator.  Create a slab context as a child of
CacheMemoryContext in RelationCacheInitialize() and allocate all
RelationData structs there; subsidiary allocations remain in
CacheMemoryContext itself.
---
 src/backend/utils/cache/relcache.c | 44 +++++++++++++++++++++++-------
 1 file changed, 34 insertions(+), 10 deletions(-)

diff --git a/src/backend/utils/cache/relcache.c b/src/backend/utils/cache/relcache.c
index dc42f2c4c1f..27eff372298 100644
--- a/src/backend/utils/cache/relcache.c
+++ b/src/backend/utils/cache/relcache.c
@@ -137,6 +137,14 @@ typedef struct relidcacheent
 
 static HTAB *RelationIdCache;
 
+/*
+ * Slab memory context holding all the relcache's RelationData structs.
+ * It is a child of CacheMemoryContext; only the fixed-size RelationData
+ * objects are allocated there, while all subsidiary data stays in
+ * CacheMemoryContext itself.
+ */
+static MemoryContext RelationSlabContext = NULL;
+
 /*
  * This flag is false until we have prepared the critical relcache entries
  * that are needed to do indexscans on the tables read by relcache building.
@@ -420,13 +428,16 @@ AllocateRelationDesc(Form_pg_class relp)
 	MemoryContext oldcxt;
 	Form_pg_class relationForm;
 
-	/* Relcache entries must live in CacheMemoryContext */
-	oldcxt = MemoryContextSwitchTo(CacheMemoryContext);
-
 	/*
-	 * allocate and zero space for new relation descriptor
+	 * Allocate and zero space for new relation descriptor.  The RelationData
+	 * struct goes into RelationSlabContext; all subsidiary data is allocated
+	 * in CacheMemoryContext.
 	 */
-	relation = palloc0_object(RelationData);
+	relation = MemoryContextAllocZero(RelationSlabContext,
+									  sizeof(RelationData));
+
+	/* Relcache subsidiary data must live in CacheMemoryContext */
+	oldcxt = MemoryContextSwitchTo(CacheMemoryContext);
 
 	/* make sure relation is marked as having no open file yet */
 	relation->rd_smgr = NULL;
@@ -1892,9 +1903,11 @@ formrdesc(const char *relationName, Oid relationReltype,
 	bool		has_not_null;
 
 	/*
-	 * allocate new relation desc, clear all fields of reldesc
+	 * allocate new relation desc, clear all fields of reldesc; the
+	 * RelationData struct itself goes into RelationSlabContext
 	 */
-	relation = palloc0_object(RelationData);
+	relation = MemoryContextAllocZero(RelationSlabContext,
+									  sizeof(RelationData));
 
 	/* make sure relation is marked as having no open file yet */
 	relation->rd_smgr = NULL;
@@ -3564,9 +3577,11 @@ RelationBuildLocalRelation(const char *relname,
 	oldcxt = MemoryContextSwitchTo(CacheMemoryContext);
 
 	/*
-	 * allocate a new relation descriptor and fill in basic state fields.
+	 * allocate a new relation descriptor and fill in basic state fields; the
+	 * RelationData struct itself goes into RelationSlabContext
 	 */
-	rel = palloc0_object(RelationData);
+	rel = MemoryContextAllocZero(RelationSlabContext,
+								 sizeof(RelationData));
 
 	/* make sure relation is marked as having no open file yet */
 	rel->rd_smgr = NULL;
@@ -3999,6 +4014,14 @@ RelationCacheInitialize(void)
 	if (!CacheMemoryContext)
 		CreateCacheMemoryContext();
 
+	/*
+	 * create the slab context holding the relcache's RelationData structs
+	 */
+	RelationSlabContext = SlabContextCreate(CacheMemoryContext,
+											"RelationSlabContext",
+											SLAB_DEFAULT_BLOCK_SIZE,
+											sizeof(RelationData));
+
 	/*
 	 * create hashtable that indexes the relcache
 	 */
@@ -6298,7 +6321,8 @@ load_relcache_init_file(bool shared)
 			rels = repalloc_array(rels, Relation, max_rels);
 		}
 
-		rel = rels[num_rels++] = (Relation) palloc(len);
+		rel = rels[num_rels++] = (Relation)
+			MemoryContextAlloc(RelationSlabContext, len);
 
 		/* then, read the Relation structure */
 		if (fread(rel, 1, len, fp) != len)
-- 
2.53.0

