If you have ever tuned a PostgreSQL instance, the first parameter you likely touched was shared_buffers. This block of memory is the heart of Postgresās performance, acting as a shared cache for data pages. However, it has a significant limitation: it is static.
In the traditional PostgreSQL architecture, the Postmaster process allocates the main shared memory segment exactly once during startup. If you need more shared memory three hours later to handle a complex parallel join, you are out of luck.
That changed with the introduction of Dynamic Shared Memory (DSM).
The Problem: The Startup Bottleneck
PostgreSQL uses a process-based architecture rather than a thread-based one. For different backend processes to talk to each other or see the same data, they must map to the same segment of shared memory.
Historically, this was handled via System V IPC or anonymous mmap. The Postmaster would request a large chunk of bytes, and every child process would inherit that mapping. The catch? The size must be known upfront. This creates a “decision” dilemma:
- Allocate too little, and you limit the scope of complex operations.
- Allocate too much, and you waste system RAM that could be used for the OS page cache.
The Solution: Dynamic Shared Memory (DSM)
Introduced in PostgreSQL 9.4, DSM allows the database to request new segments of shared memory from the operating system on the fly, long after the postmaster has started. This allows PostgreSQL to be elastic, requesting memory when a heavy task arrives and releasing it once the task is complete.
The Technical Challenge: The Pointer Problem
In the main shared memory segment, PostgreSQL attempts to map the memory to the same Virtual Address Space in every process. This allows backends to use standard C pointers to reference data.
However, with DSM, there is no guarantee that every process can map a new segment to the same address. If Backend A maps a DSM segment at address 0x7fff1000, Backend B might already have something else there and be forced to map it at 0x7fff5000.
The Solution: Offsets instead of Pointers
Because absolute pointers are unreliable in DSM, PostgreSQL developers use Relative Pointers (relptr). Instead of storing the memory address, the structure stores the offset from the base of the segment.
To access data in DSM, the process performs a simple calculation:
$$TargetAddress = BaseAddress_{current_process} + Offset$$
This ensures that even if the Start of the memory block is in a different place for every worker, they all arrive at the same data point.
Primary Applications of DSM
1. Parallel Query Execution
When you execute a large SELECT, the leader process spawns Parallel Workers. These workers need a place to:
- Share partial hash tables.
- Store temporary results for parallel aggregation.
- Exchange status information.
The leader creates a DSM segment, populates it with the required plan data, and the workers attach to it. Once the query finishes, the segment is destroyed.
2. Modern Extensions
Extensions like pg_stat_statements traditionally use fixed shared memory. However, newer extensions that require on-demand scaling use DSM to manage state without requiring a database restart to change memory limits.
3. Background Workers
Custom background workers often use DSM to create communication message queues (shm_mq) to pass data back and forth between themselves and standard backend processes.
Enabling DSM in postgresql.conf
In almost all modern installations (Postgres 9.4+), DSM is enabled by default. However, you can control the implementation method used to communicate with the OS.
The primary setting is dynamic_shared_memory_type. You can check your current setting by running:
postgres=# SHOW dynamic_shared_memory_type;
dynamic_shared_memory_type
posix
(1 row)
Options for dynamic_shared_memory_type:
posix (Default on Linux/Unix): Uses shm_open. This is generally the fastest and most reliable method.
sysv: Uses System V shared memory (shmget). Older style, often has lower OS limits.
mmap: Uses shared memory-mapped files in the data directory. Good if the OS has restrictive shared memory limits.
none: Disables DSM entirely. Warning: This will break parallel query execution and many modern extensions.
To change it: Modify your postgresql.conf and restart the server.
dynamic_shared_memory_type = posix
Conclusion
Dynamic Shared Memory transformed PostgreSQL from a rigid, static-memory engine into a flexible, parallel-processing powerhouse. By solving the “mapping problem” through clever use of offsets and OS-native memory handles, Postgres can now scale its resource usage to match the complexity of the query at hand.
While shared_buffers will always be the king of the cache, DSM is the engine of PostgreSQL’s modern concurrency.
See this in action at PGConf India 2026 āĀ Beyond shared_buffers: On-Demand Memory in Modern PostgreSQLĀ presented byĀ Vaibhav Popat.
