Enable zram Compressed Swap on Ubuntu 26.04

– min read

I was pushing memory on a 3.3 GB Proxmox VM the other week and noticed my 7 GB of disk swap barely budged from 5% usage despite the OOM killer starting to eye processes. That is when I remembered zram — Linux’s built-in compressed block device that stores swap pages in RAM before they ever touch the disk. It shipped with the kernel ages ago, but on Ubuntu the systemd-zram-generator package makes it a one-file config. Here is how I set it up.

GitHub: systemd/zram-generator
Kernel docs: zram kernel docs


DDR4 RAM memory module used in the zram swap guide illustration
RAM DDR4 module. Source, CC BY-SA 4.0.

What zram Does

Zram creates a swap device in RAM that compresses every page written to it. The kernel writes pages to zram, compresses them with lzo-rle (default on current kernels), and keeps the compressed data in system memory. When a page is read back, it decompresses on the fly. Real-world compression ratios hit 1.5–2:1 on typical server workloads — in my test, 168 MB of anonymous pages shrank to 108 MB. That is effectively 50–60% more usable swap without touching a disk spindle or SSD write cycle.


Install systemd-zram-generator

The package is in the Ubuntu repos since 24.04. One command:

sudo apt update
sudo apt install -y systemd-zram-generator

You can verify it installed with dpkg -l | grep zram-generator.


Write the Configuration

Create /etc/systemd/zram-generator.conf with a single section for the first zram device. I set mem-size-ratio=0.5 so the zram device gets half of the system RAM (1.7 GB on my 3.3 GB VM), and priority=100 to make it preferred over disk swap: Once zram is live, pair it with Glances to track real-time compression ratios.

sudo cat > /etc/systemd/zram-generator.conf << 'EOF'
[zram0]
mem-size-ratio=0.5
priority=100
zram-filesystem=swap
EOF


Start the zram Service

The generator converts the config into a systemd unit. Reload daemon files and start the setup service:

sudo systemctl daemon-reload
sudo systemctl start [email protected]


Check It Is Live

Three commands tell you everything you need:

swapon --show
NAME       TYPE      SIZE   USED PRIO
/dev/dm-1  partition   4G 395.7M   -1
/dev/zram0 partition 1.7G     0B  100

zramctl
NAME       ALGORITHM DISKSIZE DATA COMPR TOTAL STREAMS MOUNTPOINT
/dev/zram0 lzo-rle       1.7G   4K   80B   12K         [SWAP]

free -h
               total        used        free      shared  buff/cache   available
Mem:           3.3Gi       1.3Gi       1.4Gi       656Mi       1.6Gi       2.0Gi
Swap:          8.7Gi       407Mi       8.3Gi

swapon --show lists all swap devices; zram0 appears with priority 100, meaning the kernel prefers it over disk-based swap. zramctl shows the uncompressed data, compressed data, and total memory used by zram. free -h adds the new swap into the total.


Bar chart comparing disk swap vs zram swap size, and original vs compressed memory pages showing 1.56:1 compression ratio
Compression ratio chart from real test data on Ubuntu 26.04 (author\’s VM).


Watch zram in Action

To see the compression working, allocate memory until the system starts swapping. I used a simple Python loop that fills 1.8 GB in 200 MB chunks — this pushes pages into zram:

python3 -c "
import time
blocks=[]
for i in range(9):
    try:
        blocks.append(bytearray(200*1024*1024))
        print(f'Allocated {(i+1)*200}MB')
        time.sleep(0.2)
    except MemoryError:
        break
"

After the script finishes (or if it hits the memory limit), check zramctl again. On my runner the output changed from idle zeros to real numbers:

zramctl
NAME       ALGORITHM DISKSIZE   DATA  COMPR  TOTAL STREAMS MOUNTPOINT
/dev/zram0 lzo-rle       1.7G 168.6M 108.3M 111.5M         [SWAP]

168.6 MB of anonymous pages compressed to 108.3 MB — a ratio of about 1.56:1. The 111.5 MB under TOTAL is the actual RAM the zram device consumes (compressed data plus metadata), meaning I saved roughly 60 MB of physical memory compared to what would have been written to disk. For a 3.3 GB VM that is a small but meaningful bump.

The demo data is synthetic — in real server workloads the load is sustained across many processes, so the compression ratios tend to be even higher (text-heavy pages compress better than bytearrays). Test it with your own app stack: run stress --vm 4 --vm-bytes 512M --timeout 30 if you prefer the stress package, then check zramctl.


Tune vm.swappiness for zram

Because zram lives in RAM, swapping to it does not hit a disk bottleneck. For servers on SSDs or in VMs I raise vm.swappiness so the kernel is less reluctant to swap. The default 60 works, but 100 tells the kernel to prefer swap over dropping file caches:

echo "vm.swappiness = 100" | sudo tee /etc/sysctl.d/90-zram-swap.conf
sudo sysctl -p /etc/sysctl.d/90-zram-swap.conf

The result: the kernel aggressively moves inactive memory pages to zram, freeing up physical RAM for active processes and file cache. If you want alerts when swap crosses a threshold, my uptime monitoring script with Telegram alerts fits right in. If you run bare metal with spinning rust, keep swappiness at the default 60 — zram still beats disk swap, but aggressive swap-out on HDDs hurts interactive latency.


My 3.3 GB VM now has 1.7 GB of compressed swap in addition to its existing 7 GB disk swap. The real-world compression ratio of 1.56:1 means I effectively extended memory without adding a single byte of hardware — and zram keeps the write-heavy swap traffic off the SSD, which matters on a hypervisor hosting guests. Zram complements my other homelab services — from a WireGuard VPN server to monitoring stacks. Links are at the top of this post.

Mohamad ZulfahmyCybersecurity · OffSec · Entrepreneur
About me ↗
ON THIS PAGE
On this page