Debian 13: ZRAM/Zswap — when it saves your box and when it backfires

Was this helpful?

You know the moment. The box “has plenty of RAM,” the graphs looked fine yesterday, and now SSH pauses between keystrokes like it’s thinking about its life choices.
Load average is climbing, disks are lit up, and every restart request from a developer sounds like a threat.

ZRAM and zswap can be the difference between a graceful slowdown and a full-blown outage. They can also be the reason your CPU is pegged at 100% doing compression cosplay while latency burns.
Debian 13 gives you enough knobs to save the system—or to build a very efficient failure mode.

The mental model: what zram and zswap actually do

ZRAM: a compressed block device living in RAM

ZRAM creates a RAM-backed block device (like /dev/zram0) and lets the kernel treat it like a swap device.
When the kernel decides to swap out a page, that page can land in zram, compressed.
The “disk” is memory, but you gain effective capacity because pages are compressed. You pay in CPU cycles.

Think of zram as “swap without storage,” which sounds like a paradox until you remember: pages are often compressible (zero-filled, repetitive data, old heap garbage, cached JSON you shouldn’t have kept, etc.).
In a crunch, compressing 4 GiB of cold pages into 2 GiB of RAM is a win. Compressing 4 GiB into 3.9 GiB is just an expensive way to be disappointed.

Zswap: a compressed cache in front of a real swap device

Zswap is different. It’s not a swap device. It’s a cache for swapped pages, stored compressed in RAM, sitting in front of your actual swap (partition or swapfile).
When pages are swapped out, zswap tries to keep them compressed in memory. If the zswap pool fills, it evicts pages to the real swap device.

This makes zswap a “write reducer” and latency smoother: fewer writes to SSD/HDD, less random IO under pressure, better tail latencies when the system is thrashing.
But it still depends on having a proper swap backend. No swap device, no zswap safety net.

The operational difference that matters

  • zram can replace disk swap on small systems, or become the “fast swap tier” ahead of disk if you also keep disk swap around.
  • zswap is a cache; it reduces swap IO but does not replace swap capacity.
  • Both are forms of trading CPU for memory. On modern CPUs, that trade is often good. On busy systems, it can be ruinous.

One paraphrased idea often attributed to Jim Gray: “Measure before you tune; most tuning is guesswork without data.” (paraphrased idea)
Memory compression is a perfect example. It’s easy to be clever. It’s harder to be correct.

Joke #1: Memory compression is like vacuum-sealing your closet. It works great until you need that one shirt during a fire drill.

Facts and context: how we got here (and why it matters)

Some context turns “random kernel knob fiddling” into actual engineering. Here are a few concrete facts worth keeping in your head:

  1. zram started life as “ramzswap” years ago, then got renamed and upstreamed; the idea was always “compressed swap in RAM,” not a general cache.
  2. zswap landed as a frontswap backend, meaning it hooks into the swap subsystem as a cache layer rather than a block device.
  3. Compression algorithms changed the game: LZO was popular early for speed; LZ4 became common; ZSTD gained traction for better ratios at acceptable cost.
  4. Linux’s memory accounting got stricter over time (cgroups v2, PSI, better reclaim behavior), making “it feels slower” diagnosable with real signals.
  5. Chrome and modern browsers made swap normal again on desktops: huge working sets with lots of cold tabs, highly compressible in places.
  6. SSDs made swap viable but not free: latency is good compared to spinning disks, but sustained random writes under pressure still murder tail latency and can amplify wear.
  7. Containers made swap political: some orgs ban swap for nodes, others rely on it; memory compression becomes a middle ground when you want grace without lying to yourself.
  8. Kernel defaults are conservative: most distros avoid aggressive zram/zswap defaults because the “wrong” default becomes a support nightmare.
  9. Debian’s strength is predictability, which is why you often have to opt in to fancy things—and why you should test like an adult when you do.

When zram/zswap saves your box (and when it won’t)

Use zram when: you need “some swap” but storage is slow, fragile, or absent

zram shines on:

  • Small VMs where the hypervisor storage is noisy or thin-provisioned and swap IO causes cluster-level problems.
  • Edge boxes with cheap flash where swap wear is a real concern.
  • Developer laptops with bursty memory pressure: builds, browsers, IDEs, and “I forgot my Docker was running.”
  • Systems with plenty of CPU headroom and moderate memory pressure: compression cost stays under control.

What you’re buying: the ability to avoid OOM kills in mild-to-moderate pressure and a reduction in disk swap churn.
What you are not buying: infinite memory. If your working set truly exceeds RAM by a lot, zram just changes how you fail.

Use zswap when: you want to keep real swap, but make it less awful

zswap shines when you already have swap on SSD/NVMe (or even HDD) and want to smooth out the worst behavior under reclaim:

  • Databases and JVMs where even small swap-in latencies can create long tail latency, but you still want a pressure release valve.
  • VM hosts where swap IO storms cause storage contention; zswap reduces write amplification.
  • Mixed workloads where “some pages are cold and compressible” is true, but you can’t predict which ones.

Don’t bother when: the bottleneck is not memory pressure

If you’re CPU-bound already, adding compression is like hiring an accountant during a kitchen fire because they’re “good with numbers.”
If you’re IO-bound because of unrelated disk workloads, zswap can help by reducing swap IO—but it won’t fix the underlying disk contention.

Hard truth: compression is not a substitute for capacity planning

zram/zswap are great “graceful degradation” tools. They are not a license to run 28 GiB of services on a 16 GiB VM.
If your steady-state working set is larger than RAM, the correct fix is more RAM, less load, or both.
Compression can buy you time. It rarely buys you peace.

How it backfires: failure modes that look like “Linux is slow”

Backfire #1: CPU saturation from compression

The most common failure mode is simple: the system is under memory pressure, it starts swapping, and now it’s also compressing/decompressing.
If your CPUs are already busy, that extra work pushes you into a death spiral: less CPU for the application, more stalls, more backlog, more memory churn.

This happens a lot with:

  • busy web nodes with per-request allocations and high GC pressure,
  • CI runners doing lots of parallel builds,
  • any box where you tried to “fix memory” by enabling ZSTD at a high compression level without measuring.

Backfire #2: false sense of stability (“it stopped OOMing”) followed by latency collapse

zram especially can turn an immediate OOM into a prolonged period of misery.
The system doesn’t die. It just becomes unusable: interactive latency spikes, RPC timeouts, watchdog resets, and the on-call learns new swear words.

On servers, the right question isn’t “did we avoid OOM?” It’s “did we preserve SLOs?”
Sometimes killing one process fast is kinder than keeping everything half-alive for 20 minutes.

Backfire #3: reclaim fights your workload

Swap activity is not inherently evil, but aggressive reclaim can be.
If your workload’s hot set is large and constantly shifting (e.g., caches that churn, analytics jobs, or high-cardinality metrics), the kernel may evict pages you will need again soon.
With zram/zswap, you’re now paying extra overhead for a cycle of “compress, store, decompress, fault back.”

Backfire #4: mis-sized pools and “swap priority” surprises

You can run disk swap and zram together. The kernel chooses based on swap priority.
Get that wrong and you can accidentally shove pages to disk first, keeping zram mostly idle while your SSD screams.
Or the reverse: you can fill zram too aggressively, leaving too little real RAM for page cache and application working sets.

Backfire #5: zswap pool full + slow backend = sudden cliff

zswap looks great until the pool fills. Then it has to evict to the real swap backend.
If that backend is slow or contended, you go from “nice” to “oh no” quickly.
It’s not that zswap broke; it’s that you were living on borrowed latency.

Joke #2: Turning on swap compression without measuring is like installing a turbo on a forklift. It moves faster right up until it meets physics.

Fast diagnosis playbook (first/second/third checks)

When a Debian 13 box is “slow” and you suspect memory pressure, don’t start by editing sysctl knobs.
Start by answering three questions: Are we under memory pressure? Are we swapping? Is the pain CPU or IO?

First: confirm pressure and who’s causing it

  • Check PSI (pressure stall information): are tasks stalled on memory reclaim?
  • Check major faults and swap-ins: are we actively paging?
  • Identify top RSS/anon offenders and whether they’re growing.

Second: determine whether compression is helping or hurting

  • CPU profile at a glance: is kswapd hot? Is kcompactd running? Are we burning CPU in compression paths?
  • zram stats: how full, what compression ratio, what read/write rates?
  • zswap stats: pool size, same-filled pages, reject/duplicate counts, and evictions to disk.

Third: pick the least-bad mitigation

  • If the system is thrashing: reduce concurrency, shed load, stop batch jobs, or temporarily restart the worst memory hog.
  • If swap backend is the bottleneck: enable/adjust zswap or add a small zram tier with correct priority.
  • If CPU is the bottleneck: lower compression cost (algorithm choice), or disable compression and accept faster OOM.

Practical tasks: commands, outputs, and decisions (12+)

These are meant to be run on a real Debian 13 host. Each task includes: a command, what the output means, and what decision you can make.
None of this is magic. It’s just disciplined observation.

Task 1: Verify whether zram devices exist and are used

cr0x@server:~$ lsblk -o NAME,TYPE,SIZE,ROTA,MOUNTPOINTS
NAME        TYPE  SIZE ROTA MOUNTPOINTS
vda         disk   80G    1
├─vda1      part   79G    1 /
└─vda2      part    1G    1 [SWAP]
zram0       disk    8G    0

Meaning: zram0 is present and shows as a disk. Size is the configured virtual size.
Disk swap is vda2.

Decision: If you expect zram but don’t see it, you’re not using it. If you see it but it’s tiny/huge, validate sizing.

Task 2: Check active swap devices and priorities

cr0x@server:~$ swapon --show=NAME,TYPE,SIZE,USED,PRIO
NAME      TYPE      SIZE   USED PRIO
/dev/zram0 partition   8G   512M  100
/dev/vda2 partition    1G     0B   -2

Meaning: zram has higher priority (100) so it will be used before /dev/vda2.

Decision: If your disk swap has higher priority than zram, fix it unless you have a deliberate reason.

Task 3: Measure overall memory and swap pressure quickly

cr0x@server:~$ free -h
               total        used        free      shared  buff/cache   available
Mem:            15Gi        12Gi       320Mi       1.1Gi       2.9Gi       1.2Gi
Swap:           9.0Gi       1.0Gi       8.0Gi

Meaning: “available” is the key number for short-term headroom. Swap used indicates we’ve started evicting.

Decision: If available is low and swap is growing, you’re in reclaim territory. Move to PSI and vmstat next.

Task 4: Check memory PSI to see if the kernel is stalling tasks

cr0x@server:~$ cat /proc/pressure/memory
some avg10=0.42 avg60=0.30 avg300=0.18 total=43832490
full avg10=0.07 avg60=0.05 avg300=0.02 total=8203491

Meaning: “some” shows reclaim contention; “full” indicates severe stalls where tasks can’t make progress due to memory pressure.

Decision: If “full avg10” is non-trivial for a latency-sensitive service, you’re past “tuning” and into mitigation: reduce load, kill offenders, add RAM.

Task 5: Watch swap-in/out and reclaim behavior live

cr0x@server:~$ vmstat 1 5
procs -----------memory---------- ---swap-- -----io---- -system-- ------cpu-----
 r  b   swpd   free   buff  cache   si   so    bi    bo   in   cs us sy id wa st
 2  1  942080 332000  60200 812000  120  240    14    90  820 1280 40 10 35 15  0
 1  2  954368 318000  60180 810500  200  420     0   140  900 1400 45 12 28 15  0
 3  1  990720 290000  60150 808900  320  500     0   210 1050 1600 52 13 20 15  0
 2  2 1015808 270000  60120 807400  410  690     0   260 1120 1750 55 15 16 14  0
 2  1 1048576 250000  60090 805100  300  520     0   180  980 1500 50 13 22 15  0

Meaning: si/so are swap-ins/outs per second. Sustained non-zero values suggest active paging.
CPU wa indicates IO wait; if it spikes during swapping, backend swap may be painful.

Decision: High si suggests you’re paying the cost now (faulting back in). High so suggests you’re pushing pages out. Either way, find the memory hog and decide: kill/restart/throttle.

Task 6: Determine if the box is slow due to disk swap IO

cr0x@server:~$ iostat -xz 1 3
Linux 6.12.0 (server)  12/30/2025  _x86_64_  (8 CPU)

avg-cpu:  %user   %nice %system %iowait  %steal   %idle
          45.12    0.00    9.20   18.44    0.00   27.24

Device            r/s     rkB/s   rrqm/s  %rrqm r_await rareq-sz     w/s     wkB/s   wrqm/s  %wrqm w_await wareq-sz  aqu-sz  %util
vda              2.00     48.00     0.00   0.00   3.50    24.00  120.00   4096.00     0.00   0.00  45.00    34.13    5.40  98.00

Meaning: Near-100% utilization and high await on the swap backend device means your storage is a bottleneck.

Decision: If disk is pegged during swapping, zswap can help. If it’s already enabled and still pegged, the backend is too slow or the system is overcommitted.

Task 7: Inspect zram compression ratio and current usage

cr0x@server:~$ cat /sys/block/zram0/mm_stat
786432000 196608000 131072 0 0 0 0 0

Meaning: The fields vary by kernel, but typically include: original data size, compressed size, and metadata.
Here, ~750MB of original pages compressed to ~187MB: a good ratio.

Decision: If compressed size is close to original size, zram is giving you little benefit; consider a faster algorithm, smaller zram, or disabling if CPU is suffering.

Task 8: Check which algorithm zram uses

cr0x@server:~$ cat /sys/block/zram0/comp_algorithm
lzo [lz4] zstd

Meaning: The algorithm in brackets is active (lz4).

Decision: For servers, prefer lz4 for speed unless you’ve proven ZSTD improves ratio enough to reduce paging significantly.

Task 9: Verify whether zswap is enabled and what it’s doing

cr0x@server:~$ cat /sys/module/zswap/parameters/enabled
Y
cr0x@server:~$ grep -H . /sys/kernel/debug/zswap/*
/sys/kernel/debug/zswap/pool_total_size: 268435456
/sys/kernel/debug/zswap/stored_pages: 23144
/sys/kernel/debug/zswap/same_filled_pages: 120
/sys/kernel/debug/zswap/duplicate_entry: 340
/sys/kernel/debug/zswap/reject_reclaim_fail: 0
/sys/kernel/debug/zswap/reject_compress_poor: 42
/sys/kernel/debug/zswap/written_back_pages: 1800

Meaning: zswap is enabled. It’s storing pages in the pool, rejecting some for poor compression, and writing some back to disk.

Decision: A high written_back_pages rate plus slow disk suggests the pool is too small, memory pressure is too high, or the swap backend is the real problem.

Task 10: Confirm the kernel swap policy knobs (swappiness and friends)

cr0x@server:~$ sysctl vm.swappiness vm.vfs_cache_pressure vm.page-cluster
vm.swappiness = 60
vm.vfs_cache_pressure = 100
vm.page-cluster = 3

Meaning: swappiness influences how eagerly the kernel swaps vs reclaims page cache. page-cluster affects swap readahead patterns.

Decision: If you run zram-only swap on a latency-sensitive box, consider lowering swappiness (often 10–30) to avoid swapping out anonymous pages too eagerly. Measure after.

Task 11: Identify top memory consumers (RSS/anon) without fooling yourself

cr0x@server:~$ ps -eo pid,comm,rss,%mem --sort=-rss | head -n 10
  PID COMMAND           RSS %MEM
 2210 java          4123456 26.1
 1842 postgres      2104320 13.3
 3011 node          1456896  9.2
 1123 prometheus     802560  5.1

Meaning: RSS is resident set size: what’s currently in RAM. Under pressure, RSS can drop while performance collapses because the process is faulting pages in/out.

Decision: If a process is huge and growing, you either cap it (limits), tune it (heap, caches), or treat it as an incident. Don’t “just add more zram” to avoid the conversation.

Task 12: Check major page faults to confirm real paging pain

cr0x@server:~$ pidstat -r 1 3
Linux 6.12.0 (server)  12/30/2025  _x86_64_  (8 CPU)

12:20:01 PM   UID       PID  minflt/s  majflt/s     VSZ     RSS   %MEM  Command
12:20:02 PM  1000      2210   2300.00     12.00 6123456 4123456  26.1  java
12:20:02 PM  1000      1842    820.00      6.00 3256780 2104320  13.3  postgres
12:20:03 PM  1000      2210   2500.00     20.00 6123456 4123456  26.1  java

Meaning: Major faults (majflt/s) require disk or swap access (or at least a non-trivial fault path). If major faults rise with latency spikes, you’re paging in anger.

Decision: If major faults are sustained, focus on reducing working set and swap churn. Compression might help if it reduces disk IO; it won’t fix an oversized workload.

Task 13: Confirm cgroup v2 memory limits (container hosts love to lie)

cr0x@server:~$ cat /sys/fs/cgroup/memory.max
max
cr0x@server:~$ cat /sys/fs/cgroup/memory.current
12582912000

Meaning: No cgroup limit at the root; current usage is ~11.7GiB. For containers/services, check their individual cgroups too.

Decision: If a service has a too-tight limit, it may thrash inside its cgroup even when the host has memory. Fix the limit before tuning swap.

Task 14: Check zram activity rates via /proc/swaps and /proc/vmstat

cr0x@server:~$ cat /proc/swaps
Filename				Type		Size		Used		Priority
/dev/zram0                               partition	8388604		524288		100
/dev/vda2                                partition	1048572		0		-2
cr0x@server:~$ egrep 'pswpin|pswpout' /proc/vmstat
pswpin 184233
pswpout 392001

Meaning: Total swap-in/out counts let you correlate “slow periods” with paging.

Decision: If pswpin climbs during incidents, you’re paying swap latency. If only pswpout climbs, you’re pushing pages out (maybe proactively due to swappiness).

Tuning guidance: the knobs that matter on Debian 13

Pick your strategy: zram-only, zswap-only, or a tiered setup

Here’s the production take:

  • zram-only: good for small systems and edge devices where disk swap is unacceptable. Risk: prolonged thrash instead of quick OOM.
  • zswap-only: best general-purpose choice when you already have swap on SSD/NVMe. It reduces IO without pretending RAM is infinite.
  • tiered (zram + disk swap): powerful when you set priorities correctly. zram absorbs the churn; disk swap is the last resort.

Algorithm choice: don’t be clever before you’re stable

For zram and zswap, algorithm choice is a policy decision:

  • LZ4: fast, decent ratio, usually the safest default for servers.
  • LZO: also fast, sometimes slightly worse ratio than LZ4.
  • ZSTD: better ratio, higher CPU cost; can be excellent if it prevents disk IO, disastrous if CPU is already tight.

My rule: if you’re diagnosing an incident, choose speed. If you’re designing a steady-state setup on a CPU-rich box, experiment with ZSTD—but measure “full” memory PSI and tail latency.

Sizing zram: stop treating it like free RAM

Common zram sizing advice floats around like folk medicine (25%, 50%, “equal to RAM,” etc.).
In production, zram size is about what you want the system to survive, not what you want it to pretend.

  • On servers: start around 10–25% of RAM if you’re using it as a fast tier, not as a capacity crutch.
  • On laptops/desktops: 25–50% of RAM is often reasonable because interactive workloads benefit and you can tolerate some CPU overhead.
  • On tiny systems (≤ 2–4 GiB RAM): zram can be bigger proportionally, but be careful: compression CPU on small cores can be the bottleneck.

zswap sizing: control the pool and eviction behavior

zswap’s pool has a maximum percent of RAM and it uses an allocator (often zbud/z3fold) that trades density for CPU and fragmentation characteristics.
If the pool is too small, you write back to disk quickly and lose the point. Too large, and you crowd out page cache and anonymous hot pages.

A sane start for servers with SSD swap is often a pool cap in the 10–20% RAM range.
If you frequently hit writeback under normal load, you’re underprovisioned or your workload is spiky enough that you should revisit limits and concurrency.

Swappiness: you can’t win a policy argument with a single integer

vm.swappiness is not “how much swap do I want.” It’s part of a decision system about reclaiming page cache vs anonymous memory.
With zswap, higher swappiness can be okay because swap-outs might stay in RAM compressed, reducing IO. With zram-only, too high swappiness can cause unnecessary churn.

Practical take:

  • Latency-sensitive servers: start around 10–30 and test.
  • General-purpose boxes: defaults (60) may be fine, especially with zswap.
  • Cache-heavy services: you may want a higher value if page cache reclaim is desirable, but only if you understand the tradeoffs.

What Debian 13 admins should standardize

Standardize two things across fleets:

  1. Visibility: export PSI (/proc/pressure/*), swap-in/out (/proc/vmstat), and zram/zswap stats. If you can’t see it, you’ll blame “Linux.”
  2. Policy: decide per node class whether swap is allowed and whether it’s zswap, zram, or both. Consistency beats cleverness at 3 a.m.

Three corporate mini-stories from the trenches

Mini-story 1: The incident caused by a wrong assumption

A mid-sized company ran a fleet of Debian VMs for internal APIs. The platform team enabled zswap on new images.
The assumption was tidy: “zswap means swapping is cheap now, so we can stop worrying about swap storms.”
They also quietly reduced swap size to “just in case,” because they didn’t want disk usage to surprise anyone.

Months later, a routine deployment increased memory use by a few hundred megabytes per instance.
Nothing dramatic. No single process went rogue. The kind of slow creep that makes graphs look like gentle hills.
Under peak load, nodes began timing out. Not crashing—timing out. Retries spiked, which increased load, which increased memory churn. Classic.

On-call found zswap enabled and healthy. The pool filled, then started writing back to the backend swap.
But the backend swap was tiny, so it filled quickly too. Once swap is full, the kernel has fewer options; you get reclaim pressure, stalls, and eventually OOM—often at the worst possible time.
The system didn’t have a big swap safety net; it had a small swap trap.

Fix was boring: restore a reasonable swap backend size, keep zswap, and alert on zswap pool saturation and swap usage growth rate.
The team also added a “memory budget” check to deployments: small per-node increases can turn into big fleet-wide failure patterns.

Mini-story 2: The optimization that backfired

Another org ran CI runners on Debian. Builds were parallelized aggressively, and memory pressure was expected.
Someone read that ZSTD had better compression ratios and decided to “upgrade performance” by switching zram to ZSTD everywhere.
The change looked great in a quiet test: swap usage dropped, and “free memory” looked better.

In production, CPU was the real scarce resource. Those runners were already busy compiling, linking, compressing artifacts, and doing crypto handshakes to registries.
When memory pressure hit, the system began compressing pages with ZSTD. CPU went from “busy but fine” to “saturated and chaotic.”
Build times increased. Queue times increased. Engineers added more parallel jobs to compensate, which made it worse.

The clue was in the metrics they weren’t watching: memory PSI “full” rose during peak hours, and CPU steal on the hypervisor increased as everyone fought for cycles.
The “better compression ratio” was irrelevant; the system didn’t need more effective swap capacity. It needed less CPU overhead under contention.

They rolled back to LZ4, reduced zram size slightly, and added a scheduling policy to cap concurrent builds based on available memory and PSI thresholds.
The net result: fewer heroic kernel tricks, better throughput, and fewer mysterious slowdowns.

Mini-story 3: The boring but correct practice that saved the day

A payments-adjacent service (always fun) ran on Debian with a strict latency budget. The SRE team had a policy: swap is allowed, but only with zswap, and only with specific alerts.
They tracked memory PSI, swap-in rate, and disk await times. Nothing fancy. Just consistent visibility.

One afternoon, a traffic surge arrived alongside a harmless-looking configuration change that increased in-memory caching.
Memory usage rose, and reclaim started. The key was that the system didn’t immediately fall over; zswap absorbed early swap-outs, reducing disk writes.
But the alerts fired: memory PSI “full” nudged up, and zswap written-back pages began increasing—an early warning that the pool was filling.

The on-call didn’t guess. They followed the runbook: reduce cache size, lower worker concurrency, and scale out.
No dramatic restarts. No “let’s try zram too.” Just controlled mitigation while staying within SLOs.
The incident became a non-event: a page, a response, and a fix before customers noticed.

The practice that saved them was dull: they had leading indicators. Swap usage is a lagging indicator; by the time it’s huge, you’re already paying.
PSI and zswap writeback gave them a chance to act before the box turned into a slideshow.

Common mistakes: symptoms → root cause → fix

1) Symptom: load average is high, CPU is high, but nothing “seems” busy

Root cause: kernel threads are burning CPU reclaiming and compressing pages (kswapd, compression workqueues), often triggered by zram/zswap under pressure.

Fix: confirm with PSI and vmstat. If CPU is the constraint, switch to a faster algorithm (LZ4), shrink zram, lower concurrency, or disable compression temporarily to force faster OOM and recovery.

2) Symptom: disks hit 100% util during “memory incidents”

Root cause: swap backend is taking heavy writes/reads; zswap may be disabled, misconfigured, or too small; zram priority may be wrong.

Fix: enable zswap (with a real swap device), ensure zram (if used) has higher priority than disk, and verify disk swap isn’t on a contended device.

3) Symptom: “We enabled zram, now caches are worse and performance regressed”

Root cause: zram too large; it steals RAM from page cache and anonymous hot pages, causing more IO and faults.

Fix: reduce zram size; treat it as a small emergency buffer, not a second RAM bank. Re-test with real workload.

4) Symptom: system doesn’t OOM anymore, but becomes unresponsive for minutes

Root cause: thrashing: working set exceeds RAM significantly. zram makes the failure slower and more painful.

Fix: set limits, reduce memory use, or add RAM. Consider keeping a small disk swap with zswap (or no swap) depending on SLOs; decide whether quick OOM is preferable to long stalls.

5) Symptom: zswap enabled, but swap writes still heavy

Root cause: zswap pool saturates quickly; poor compression ratios (many rejects); or backend swap is used directly due to policy/priority issues.

Fix: inspect zswap debug counters; increase pool cap modestly or adjust algorithm; verify swap devices and priorities; fix the underlying memory growth.

6) Symptom: container workloads OOM inside cgroups even though host has free memory

Root cause: cgroup memory.max too low; swapping behavior differs inside the cgroup; host-level zram/zswap won’t fix a bad limit.

Fix: adjust cgroup limits, set sane per-service budgets, and monitor per-cgroup PSI if possible. Don’t use system-wide swap compression as a bandage for bad quotas.

7) Symptom: “Swap is used even when RAM is available”

Root cause: misunderstanding of Linux memory reporting; “available” vs “free,” page cache dynamics, and proactive reclaim.

Fix: use free -h and focus on “available,” use PSI to confirm pressure. Don’t knee-jerk disable swap because “swap used != bad.”

8) Symptom: suspend/resume or hibernate issues on laptops after enabling zram

Root cause: hibernation requires swap backing store large enough to write RAM image; zram isn’t suitable as the only hibernate target.

Fix: keep a disk swap partition/file sized for hibernation; use zram as additional swap with higher priority, not as the only swap.

Checklists / step-by-step plan

Checklist A: Decide what to deploy (per node class)

  1. Classify the node: laptop, VM, database, CI runner, container host, edge box.
  2. Define the failure preference: quick OOM vs graceful slowdown. For latency-critical services, quick failure is often safer.
  3. Check CPU headroom: if CPU is routinely >70% under peak, compression cost might hurt.
  4. Check swap backend quality: SSD/NVMe ok; slow networked storage or contended disks are not.
  5. Pick a strategy: zswap-only for most servers; zram-only for no-disk/slow-disk edge; tiered for noisy storage environments.

Checklist B: Safe baseline for a Debian 13 server (zswap-first)

  1. Ensure you have a real swap device (swapfile or partition) sized to your policy.
  2. Enable zswap and start with a fast algorithm.
  3. Set alerts on memory PSI “full” and swap-in rate.
  4. Load test under realistic concurrency and watch tail latency, not just throughput.
  5. Only then consider adding a small zram tier if disk swap is still the bottleneck.

Checklist C: Tiered swap (zram + disk) without self-sabotage

  1. Create/enable zram swap with higher priority than disk swap.
  2. Keep disk swap as a backstop with lower priority.
  3. Cap zram size to a conservative fraction (10–25% RAM for servers).
  4. Use LZ4 unless you have measured evidence otherwise.
  5. Monitor: zram fullness, compression ratio, swap-in/out rates, and CPU.

Checklist D: Incident response when memory pressure hits

  1. Check PSI (memory). If “full” is elevated, treat it as severity.
  2. Check swap-in rate and major faults. Confirm active paging.
  3. Check disk await/util. If pegged, IO is part of the problem.
  4. Find the top offender and decide: restart, cap, or scale out.
  5. Post-incident: fix the memory regression and add a guardrail (limit, budget, or alert).

FAQ

1) Should I use zram or zswap on Debian 13?

For most servers: zswap with a real swap backend. For small/edge devices: zram can be great. For noisy storage: tiered can be excellent if priorities are correct.

2) Can I run both zram and zswap together?

Yes, but be deliberate. zswap caches pages destined for swap devices; if one of those swap devices is zram, you can end up compressing “in front of” a compressed device. That can be redundant overhead.
The common tiered pattern is zram + disk swap, not zswap + zram, unless you’ve measured a real benefit.

3) Does swap compression prevent the OOM killer?

It can delay OOM by increasing effective capacity for cold/compressible pages. It does not eliminate OOM if the working set keeps growing.
Sometimes delaying OOM is bad: you get minutes of timeouts instead of a fast failure and restart.

4) What compression algorithm should I choose?

Start with LZ4 for servers. Consider ZSTD only after measuring CPU headroom and proving that the better ratio reduces disk swap enough to improve tail latency.

5) What’s a sane zram size?

Servers: often 10–25% of RAM when used as a fast tier. Desktops: 25–50% can work well.
If you size it “equal to RAM” and call it a day, you’re building a slow-motion outage generator.

6) Why is swap being used when there is “free” memory?

Because “free” is not “available,” and Linux uses memory for caches aggressively. Also, the kernel may swap out cold anonymous pages to preserve cache.
Look at “available” in free -h and use PSI to confirm actual stalls.

7) How do I know if zswap is actually helping?

Look for reduced disk write rates during memory pressure, lower IO wait, and stable tail latencies. In zswap stats, you want a healthy number of stored pages and manageable writeback rates.
If the pool saturates and written-back pages spike, you’re just postponing disk pain.

8) Is swap bad for databases like PostgreSQL?

Unplanned swapping is bad for latency-sensitive databases. But a small amount of swap with zswap can prevent catastrophic OOM and reduce IO storms.
The real fix is correct memory sizing and avoiding memory overcommit; zswap is a seatbelt, not a new engine.

9) Will zram reduce SSD wear?

Yes, if it replaces or reduces swap writes to disk. zswap also helps by absorbing swap-outs in RAM and writing back less.
But if you’re thrashing hard, you may still write to disk (zswap eviction) and you’ll burn CPU too.

10) Why did enabling zram make the system slower even without heavy swapping?

If zram is oversized, it consumes RAM for its own metadata and competes with page cache. The system may reclaim more aggressively or have less cache hit rate, causing more IO.
Size it conservatively and verify with workload tests.

Conclusion: next steps you can do today

If you run Debian 13 in production, treat zram/zswap like any other performance feature: opt in with intent, measure continuously, and roll back when it lies to you.
The good news is you don’t need heroics. You need a plan.

  1. Pick a default policy per node class (zswap-only is the boring winner for many servers).
  2. Add visibility: memory PSI, swap-in/out, disk await/util, and zram/zswap stats.
  3. Run a pressure test that matches reality: peak concurrency, background jobs, and noisy neighbors included.
  4. Define your failure preference: fast OOM vs slow thrash, and align swap/compression settings to it.
  5. Fix the root cause after the incident: memory budgets, limits, and sizing. Compression is not a capacity plan.

The kernel will do its best to keep your system alive. Your job is to make sure “alive” still means “useful.”

← Previous
ZFS SSD-Only Pool Tuning: Avoiding Garbage Collection Collapse
Next →
Vulkan vs DirectX: Is a New API War Coming?

Leave a comment