Skip to main content

Why I use zswap on my laptop

·10 mins

Recently, I have been using a laptop with less RAM than I need. Most of what I do on a laptop is web browsing and writing code, usually Rust, and I use a few tools (Zed, Spotify, Obsidian). Nothing crazy, really.

I currently use Fedora as my Linux distro of choice. Fedora happens to come with zram enabled by default.

However, the combination of having less RAM, using Fedora which uses zram, and using my system in a way that has very spiky memory consumption (usually caused by rustc and rust-analyzer), led to a few occasions where I ran out of memory and applications were killed. That led me to disable zram and instead configure zswap, which fixed my issues and made my system more stable and snappy.

In this post, I want to share why I did that, what the differences are, and why I feel like zswap is a better fit for my needs (and maybe yours, too).

What is swap? #

Memory is a limited resource, especially on mobile systems (such as my laptop, which only has 16 GiB). When it runs out, the kernel has no choice but to kill applications that use a lot — this is called OOM (Out Of Memory) killing.

Fortunately, there is a better option than killing processes. Applications typically do not need to access all of the data that they have in memory at the same time. For example, a browser may only really need to access the data of the current tab that is open, and may not need to access the data of other tabs that are not currently visible.

This is where swapping comes in. The Linux kernel is able to offload unused pages of memory to somewhere else. For example, tabs in your browser that you are not actively interacting with may have their memory swapped out. This frees up space for other applications that do need memory to run.

Regular swap is the simplest strategy. Pages of memory that are not currently in use are written to a swapfile on the disk, and when they are needed again, they are read back from the swapfile.

RAM on a computer with swapfile

The downside with swap is that the disk is quite a lot slower than memory. If your system is running low on memory and has to start doing a lot of swapping, memory accesses will be slowed down significantly.

The latency numbers for disk access (SSD) and compression in the diagrams are taken from Latency Numbers Every Programmer Should Know and may not be accurate for your system, but serve as a rough guide for understanding.

Compressed swap with Zram #

zram uses a different approach. It does not use the disk as a swap device. Instead, it designates a portion of memory as a compressed swap area. Pages of memory that are not currently in use are compressed and stored in this area, and when they are needed again, they are decompressed and read back from memory.

RAM on a computer with zram enabled

So, the core idea of zram is that it increases the effective size of your RAM, because parts of your RAM that are not actively used can be compressed. If you allocate 4 GiB of your physical RAM for the compressed pool, and you can hit a compression ratio of 2.45, it can fit 9.8 GiB of uncompressed data in that area. The tradeoff is that accessing this data is slower than regular RAM access because it needs to be decompressed first.

If your total RAM is 16 GiB, this means you get an effective memory size of 21.8 GiB.

$$ \begin{align*} M_{raw} &= 16\,\text{GiB}\\ M_{compressed} &= 4\,\text{GiB}\\ \rho &= 2.45\\ M_{effective} &= M_{raw} - M_{compressed} + M_{compressed} \cdot \rho \\ &= 16 - 4 + 4 \cdot 2.45\,\text{GiB}\\ &= 21.8\,\text{GiB} \end{align*} $$

This does work in practice. That figure of 2.45 is a compression ratio you can expect to see in the real world.

The downside is that zram does not use the disk as a swap device. If your system has a low amount of memory, zram can help stretch that a bit due to the compression, but if what you are doing has spikes in memory usage, your programs may still run out of memory and be terminated.

On my laptop, I was getting out-of-memory errors when using zram, so it wasn’t working so well for me.

What is zswap? #

zswap is a Linux kernel feature that combines the benefits of regular swap and zram. It was introduced in Linux 3.11 (2013), a couple of years after zram first appeared in Linux 3.2 (2012). Pages of memory that are not currently in use are compressed and stored in RAM first, and allowed to spill over into a disk-based swap device if necessary.

RAM on a computer with zswap enabled

From the kernel’s documentation:

Zswap is a lightweight compressed cache for swap pages. It takes pages that are in the process of being swapped out and attempts to compress them into a dynamically allocated RAM-based memory pool. zswap basically trades CPU cycles for potentially reduced swap I/O. This trade-off can also result in a significant performance improvement if reads from the compressed cache are faster than reads from a swap device.

Some potential benefits:

  • Desktop/laptop users with limited RAM capacities can mitigate the performance impact of swapping.
  • Overcommitted guests that share a common I/O resource can dramatically reduce their swap I/O pressure, avoiding heavy handed I/O throttling by the hypervisor. This allows more work to get done with less impact to the guest workload and guests sharing the I/O subsystem
  • Users with SSDs as swap devices can extend the life of the device by drastically reducing life-shortening writes.

The rough idea is that you get the best of both regular swap and zram. By using memory compression first like zram, you get the fast memory access of zram and avoid slower disk I/O when memory is running low. But by also being able to evict pages to disk, you don’t run into out-of-memory issues as quickly when there is a sudden spike in memory usage.

How do they compare? #

Regular swapzramzswap
How it worksInactive pages written to diskInactive pages compressed in RAMInactive pages compressed in RAM first, spilling to disk only if the pool is full
Effective memoryRAM + swap sizeRAM + pool size × (ratio − 1)RAM + pool size × (ratio − 1) + swap size
OOM riskLowHighLow
SpeedSlow — disk I/O on every swap accessFast — RAM access with a small CPU cost for (de)compressionFast while pages are in the pool; slower only when spilling to disk
Disk wearHigh — every swap access is a disk read or writeNone — everything stays in RAMLow — disk is only used as a last resort for cold pages
DisadvantagesDisk I/O bottleneck hurts performance under memory pressureNo disk fallback — OOM is possible under heavy or spiky workloadsNot enabled by default on Fedora — requires a small amount of setup

In my opinion, zswap is the best strategy for most desktop and laptop users. It is better than regular swap, because the compression means fewer and smaller disk writes. And it is better than zram for most workloads, because the disk fallback means you can safely swap out pages that are very rarely used — keeping fast compressed memory for the things you actually need — without risking OOM kills when memory pressure spikes.

The one case where zram has an edge is if your disk is very slow or you are particularly concerned about disk wear, since zram never touches the disk at all. This is true, for example, on embedded systems that use cheap flash storage with limited write cycles.

How do you enable zswap? #

If you want to use zswap on Fedora, you first need to disable zram, and set up a regular disk-backed swap device. Then you can enable zswap by adding the appropriate kernel boot parameters.

Disabling zram on Fedora #

The documentation suggests:

sudo touch /etc/systemd/zram-generator.conf
sudo dnf remove zram-generator-defaults

Enabling regular swap on Fedora #

Fedora installations usually come with btrfs as the default filesystem. Creating a swap file on btrfs requires some extra steps. The easiest way to do it is to run this command:

sudo btrfs filesystem mkswapfile -s 16g /swapfile

Then you can add the swapfile to your system by editing the /etc/fstab file and adding a line like this:

/swapfile none swap defaults 0 0

After rebooting, you should have a regular swap device available, which you can verify with the swapon command:

swapon --show

Enabling zswap on Fedora #

To enable zswap, you need to add some parameters to your kernel boot options. In general, these are the three parameters that you want to set:

ParameterValueDescription
zswap.enabled1Enables zswap
zswap.compressorlz4Sets the compression algorithm to use, lz4 prioritizes speed over compression ratio, which is a good trade-off here
zswap.max_pool_percent25Sets the maximum percentage of RAM to use for zswap

To add these, at least on Fedora, you can edit the /etc/default/grub file and add the parameters to the end of the GRUB_CMDLINE_LINUX line. With these modifications, this is what my GRUB_CMDLINE_LINUX looks like in /etc/default/grub file looks like:

GRUB_CMDLINE_LINUX="rhgb quiet zswap.enabled=1 zswap.compressor=lz4 zswap.max_pool_percent=25"

After that, run grub2-mkconfig to update the bootloader configuration (you may need a different command if you use UEFI).

sudo grub2-mkconfig -o /boot/grub2/grub.cfg

The changes will only take effect after you reboot your system.

There is one more configuration option worth tweaking. There is a sysctl configuration vm.swappiness that controls how eagerly the system moves inactive memory from RAM to swap. When you use regular disk-based swap, you don’t want to set it too high, as that would cause the system to swap too often. However, when you use zswap, under normal circumstances, swapping just means compressing memory and storing it in zswap’s pool. So setting vm.swappiness to a higher value is beneficial, because it leads to inactive memory being compressed faster.

You can set vm.swappiness to a higher value by creating a /etc/sysctl.d/99-swappiness.conf file with the following contents:

vm.swappiness = 80

Monitoring zswap #

After you have enabled zswap, you can monitor how it performs and maybe tweak some of the parameters (swappiness and max_pool_percent). The easiest way to peek inside is to use the zswap-cli command, which you can install with dnf install zswap-cli.

$ sudo zswap-cli --stats
ZSWAP KERNEL MODULE SETTINGS:
ZSwap enabled: Y.
Maximum pool percentage: 25.
Compression algorithm: lz4.
Accept threshold percentage: 90.
Shrinker enabled: Y.

ZSWAP KERNEL MODULE USAGE SUMMARY:
Pool: 2314.97 MiB (15.1% of MemTotal).
Stored: 5668.91 MiB (86.3% of SwapUsed).
Compression ratio: 2.45.

[...] (output truncated)

This will tell you how many pages are currently in the zswap pool and how many have been compressed, the effective compression ratio, and some other statistics.

Conclusion #

If you use a laptop that has a bit less RAM than you need, zswap can be a great way to reduce your swap usage and improve your system’s performance. However, if you use a desktop or server that has a lot of RAM, you may not need zswap at all. It all depends on your specific use case.

In my experience, zswap deals really well with the kind of usage patterns that you would expect from a developer who has a lot of applications running simultaneously (browsers, IDEs, terminals, maybe the odd database in a Docker container) but only really uses one thing at a time, and has a very spiky workload (e.g. compiling code, running tests). The main issue I was running into with zram was simply running out of memory — enabling zswap means that all of those browser tabs I inevitably have open can be compressed and stored in RAM, or spill over to disk, freeing up space for rustc and rust-analyzer instead of getting processes killed.

I think that Apple configures something similar on their hardware, if you are curious about how this kind of approach plays out at a larger scale: How Memory Works in macOS (why Apple can get away with shipping computers with 8 GB of RAM).

Hayden James has also written a great article I was wrong! zswap IS better than zram, if you are curious.