With the price of RAM getting out of control, it might be a good idea to remind Linux users to enable ZRAM so they can get better performance without upgrading memory, or save money on their next single board computer by selecting a board with the right amount of memory.
I had already written about the subject when I enabled ZRAM on a ODROID-XU4Q in 2018 using zram-config, and did the same on my Ubuntu laptop at the time. In recent days, I found Firefox crashing often due to running out of memory on my system with 16GB of RAM, and the Linux 7.0 release reminded me about ZRAM, since there were some related changes. So I decided to check the current swap configuration on my Ubuntu 24.04 laptop:
|
1 2 3 4 5 6 7 8 9 10 11 |
jaufranc@CNX-LAPTOP-5:~$ zramctl NAME ALGORITHM DISKSIZE DATA COMPR TOTAL STREAMS MOUNTPOINT /dev/zram0 lzo-rle 7.6G 6.6G 2.1G 2.1G [SWAP] jaufranc@CNX-LAPTOP-5:~$ swapon NAME TYPE SIZE USED PRIO /swapfile file 8G 5.6G -2 /dev/zram0 partition 7.6G 7.3G 5 jaufranc@CNX-LAPTOP-5:~$ free -mh total used free shared buff/cache available Mem: 15Gi 9.6Gi 4.3Gi 2.4Gi 3.4Gi 5.7Gi Swap: 15Gi 12Gi 2.7Gi |
lzo doesn’t look like a recent compression algorithm, and I think I’ve seen Zstandard compression used on other systems before. However, the zram-config utility appears to be an older solution, and it’s now been replaced with zram-tools. So I decided to replace it. If you haven’t already enabled ZRAM with zram-config, you don’t need to do that, but in my case, I had to disable swap and purge the package:
|
1 2 3 4 5 |
sudo swapoff -a sudo swapoff /dev/zram0 2>/dev/null || true echo 1 | sudo tee /sys/block/zram0/reset 2>/dev/null || true sudo modprobe -r zram sudo apt purge --autoremove zram-config |
Once done, I installed zram-tools:
|
1 |
sudo apt install zram-tools |
and edited the /etc/default/zramswap file as follows:
|
1 2 3 4 5 6 7 8 9 10 11 12 |
# Compression algorithm selection ALGO=zstd # Specifies the amount of RAM that should be used for zram # based on a percentage the total amount of available memory # This takes precedence and overrides SIZE below PERCENT=75 ... # Specifies the priority for the swap devices, see swapon(2) # for more details. Higher number = higher priority # This should probably be higher than hdd/ssd swaps. PRIORITY=100 |
To be on the safe side, you may want to check zstd if supported by your kernel:
|
1 2 |
jaufranc@CNX-LAPTOP-5:~$ cat /sys/block/zram0/comp_algorithm lzo-rle lzo lz4 lz4hc [zstd] deflate 842 |
I then restarted the service with the new parameters:
|
1 |
sudo systemctl start zramswap.service |
Finally, let’s check if everything is enabled as expected:
|
1 2 3 4 5 6 7 8 9 10 11 12 13 |
jaufranc@CNX-LAPTOP-5:~$ cat /sys/block/zram0/comp_algorithm lzo-rle lzo lz4 lz4hc [zstd] deflate 842 jaufranc@CNX-LAPTOP-5:~$ zramctl NAME ALGORITHM DISKSIZE DATA COMPR TOTAL STREAMS MOUNTPOINT /dev/zram0 zstd 11.4G 7G 1.4G 1.5G [SWAP] jaufranc@CNX-LAPTOP-5:~$ swapon --show NAME TYPE SIZE USED PRIO /dev/zram0 partition 11.4G 7.8G 100 jaufranc@CNX-LAPTOP-5:~$ free -mh total used free shared buff/cache available Mem: 15Gi 12Gi 561Mi 2.4Gi 3.8Gi 2.8Gi Swap: 11Gi 7.8Gi 3.6Gi jaufranc@CNX-LAPTOP-5:~$ |
It looks good. The swapfile on my NVMe SSD is not used anymore, but I’ll try to use my system that way, and only re-enable it in case the system runs out of memory.
Finally, I wanted to make sure it was enabled on my Raspberry Pi 5 with 2GB of RAM, and I forgot that it’s indeed enabled by default on Raspberry Pi OS:
|
1 2 3 4 5 6 7 |
pi@raspberrypi:~ $ zramctl NAME ALGORITHM DISKSIZE DATA COMPR TOTAL STREAMS MOUNTPOINT /dev/zram0 zstd 2G 181.9M 22.7M 29.6M 4 [SWAP] pi@raspberrypi:~ $ free -mh total used free shared buff/cache available Mem: 2.0Gi 1.2Gi 213Mi 38Mi 794Mi 808Mi Swap: 2.0Gi 178Mi 1.8Gi |
Note the config for rpi-swap is in a different location: /etc/rpi/swap.conf, and follows a different format:
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 |
# This file is part of rpi-swap. # # Defaults are provided as commented-out options. Local configuration # should be created by either modifying this file, or by creating "drop-ins" in # the swap.conf.d/ subdirectory. The latter is generally recommended. # # See swap.conf(5) for details. [Main] #Mechanism=auto [File] #Path=/var/swap #RamMultiplier=1 #MaxSizeMiB=2048 #MaxDiskPercent=50 #FixedSizeMiB= [Zram] #RamMultiplier=1 #MaxSizeMiB=2048 #FixedSizeMiB= # Writeback settings (for zram+file mechanism): #WritebackTrigger=auto #WritebackInitialDelay=180min #WritebackPeriodicInterval=24h |
More details about this specific implementation can be found on GitHub. If you are using a different operating system on any SBC, you may want to check ZRAM (or zswap) is enabled.

Jean-Luc started CNX Software in 2010 as a part-time endeavor, before quitting his job as a software engineering manager, and starting to write daily news, and reviews full time later in 2011.
Support CNX Software! Donate via cryptocurrencies, become a Patron on Patreon, or purchase goods on Amazon or Aliexpress. We also use affiliate links in articles to earn commissions if you make a purchase after clicking on those links.







> More details about this specific implementation can be found on GitHub
That’s funny. They started with their zram implementation for RPi in 2025, that’s only seven years after me making zram the default on Armbian.
Oh, and they’re using zram+file. Might take those Raspberry Pi Ltd. employees another seven years to realize what zswap is (which I would prefer on systems with reliable flash storage).
[ What’s Your experience with ‘zswap’? Could it be used in parallel to ‘zram’, each being activated with different computing demand? Is it standard being compiled with most available Kernels? What else for to be careful with ‘zswap’? (thx) ]
Never use both together (for reasons and all other details check the ‘zswap-vs-zram-when-to-use-what.html’ link below).
I would use zram only in situations where you want to avoid swap hitting storage at all (the typical ‘SBC with crappy SD card’ situation). Otherwise use zswap.
[ i see, thanks for the summary. From my POV, ‘zram’ is more visible/adjustable (maybe it’s only about habits also, and zswap has to be built-in, no kernel module?), but has the difficulty with ‘cold pages’, means longer time unused memory accesses, accumulating in compressed memory. Not for production environments, but being a work around, having several zram{0..3} devices, it’s possible with swapoff/swapon toggling through the devices for removing ‘cold pages’ (with Kernels that have sufficient swapoff capability, at ~x00MB/s, guess Kernels >5.x?)
… official method would be(?):
echo 3600 > /sys/block/zram0/idle # 1h
echo idle > /sys/block/zram0/writeback
… another difference is (default) zswap compression algorithm has to be defined with Kernel compilation (being a fixed setting or set on kernel cmdline: zswap.compressor=(lwn.net Articles 751795) )? (thx) ]
Just looked up in our internal documentation. We’ve switched few years a VM running a crappy commercial software stack from zram (10GB assigned memory) to zswap (5GB now enough):
It was as easy as adding ‘zswap.enabled=1 zswap.compressor=zstd zswap.zpool=z3fold’ to kernel cmdline in /etc/default/grub. And then a simple ‘echo -e “zstd\nzstd_compress\nz3fold” >> /etc/initramfs-tools/modules’ followed by an update-grub and ‘update-initramfs -u’. And then ofc creating/using a swap partition on a fast SSD pool.
[ Do You recommend ‘vm.swappiness’ > 60 for RAM limited systems? (thx) ]
I’d recommend 120 or more with zram, that would evict more anonymous pages into zram instead of dropping file cache.
[ Thanks for the suggestion. (and an (useful) upper limit at ~140-160, without cpu constraint systems?, above that, it ‘can increase CPU usage due to compression’) Just for a reminder, with systems not (actively) utilizing zram that would be an useful number between around 10-40, therefore it’s a configuration setting that has to be adjusted for the ‘built-in’/inserted Kernel module being in use. (thx) ]
https://chrisdown.name/2026/03/24/zswap-vs-zram-when-to-use-what.html
>If in doubt, prefer to use zswap. Only use zram if you have a highly specific reason to.
There’s very little point in using zswap on SBC’s storage. You should avoid swapping anything to disk, because it would be very very slow due to typical MicroSD speeds and I/O.
RAM is so much faster, hence zram.
Yeah, this topic just seems so weird… I normally keep swap off altogether until I know that I’m needing to swap out old stuff for things like compiling/linking. When I’m done, I swapoff.
Adding an additional RAM consumer, even if compressed, seems non-sensical.
This is coming from an 8GB user. I couldn’t imagine any meaningful value with 2GB Some compiles, even single-job, can take a few GB.
Without zram oom situations kill background processes, with zram you have the ability to keep more processes online.
So is it really using more RAM.
Why do you think billions of Android devices use it?
If it’s using RAM (compressed or not), yes it’s using more RAM as opposed to kicking out to disk swap. RAM being used is RAM that’s not available to be used.
I know that compiling vscode requires me not only to use swap, but I STILL have to close most open programs, and adjust the node compile command to fit my system constraints.
I cannot fathom how adding ZRAM would remotely help me in this case. Again, even if compressed, that’s RAM that’s being occupied that would have to be swapped in/out ad nauseam, if not still causing an OOM because the compile/linking needs more than what is available after ZRAM takes its piece.
Maybe Android makes use of it because programs don’t need such a crazy amount of RAM. I don’t know the internals.
I’ve got a 6GB Android in front of me and I see 1.5GB swap used for 3 running profiles. Memfree is 216MB. That tells me that 1.5GB RAM is being taken up that could’ve been marked as Free or used as Cache (depending on how the comp ratio is).
It’s almost like a feedback-loop where a running program needs the system to kick old stuff to swap, which is in RAM, even if compressing it takes up more RAM, needing more old stuff to get kicked out.
> vscode
Thank you for reminding us all how using Microsoft cra^Wtools affects the brain 🙂
Truly appreciate the ad hominem there tkaiser. 👍
*IF* I were to throw a bone to ZRAM, I’d give it consideration if swap priorities work like giving ZRAM swap prio1 would shove as much as it can into ZRAM, then when more is needed, it kicks that ZRAM out to disk swap prio2.
If you really need convincing, here’s an example: ran an unmodified vanilla install on a low memory device, no programs open besides the terminal. Tried to compile some software and it ran out of memory, freezing the system to the point I had to do a hard reboot. Tried it again, this time with a hardware monitor program open alongside the terminal to see what was happening with RAM. Sure enough it would fill up and at that point the system would freeze. So I hard rebooted again, enabled zram with suitable values and guess what? Software compiled without filling up the RAM and freezing.
It does make a significant difference. There’s no harm in trying to see whether it works for your case since if it doesn’t, you just reboot and disable it.
I don’t understand this article.
zram (or zswap for that matters) are, iiuc, using RAM to optimize I/O (faster access to data, less I/O operations, less write to SSD, …). Which seems like a good deal….if you have RAM to spare.
I don’t see how it could benefit systems with low RAM, as the article seems to imply.
It provides more RAM through compression.
For example, it uses just 2.8GB of RAM (compressed) on my system for 13.4 GB of data:
I changed the PERCENT from 75 to 120 in the config file since compression is higher than I expected (4x to 5x).
I see. I didn’t expect such a high compression ratio !
glibc’s memory allocator by default tuned for speed, which means many arenas, data alignment, conservative memory freeing, and all the other features designed mainly for beefy servers.
zram masks the unoptimized-for-size allocation patters (which is one of the two major reason for high RAM consumption, another is memory fragmentation) by just compressing the memory, and this is effective because there’s lots of zeroed space due to alignment and multiple arenas.
Another solution to reduce overall memory usage is use alternative allocator, such as jemalloc, or non-glibc distro.
You forgot about Multi-Gen LRU. Combined with zram, it makes wonders!
https://docs.kernel.org/admin-guide/mm/multigen_lru.html
I wrote a “Linux for old PC” article long ago, before MGLRU (before kernel 6.1), but most of the covered stuff still applies. In this article I describe how to tune the system to run lots of stuff (FF with 37 tabs, heavy software) on 2GB of RAM.
https://notes.valdikss.org.ru/linux-for-old-pc-from-2007/en/
I’ve never paid any attention to this but I’m going to give it a try on an old laptop I’ve got with only 8GB of RAM
> In recent days, I found Firefox crashing often due to running out of memory on my system with 16GB of RAM,
Well, I’ve had 16GB on my work laptop since 2019 and never found how to fully use them. I even clone and build kernels under /dev/shm to avoid touching storage at all, and set my TMPDIR to /dev/shm. Regarding Firefox, mine runs with several hundred tabs (maybe 300 or so), it does indeed take lots of RAM but I never managed to make it crash on low memory condition. I’m actually the one killing it via “killall firefox-bin” when I want to reclaim memory or stop it from wasting CPU when I need to be fully idle or make more precise performance measurements on my machine.
On my backup server (Odroid-M1 with 4GB) I’m using ZRAM with the LZ4 compression algorithm. The main use of RAM on this machine is to run rsync with millions file indexes in RAM, and I found that LZ4 was a good compromise between compression ratio and performance on this machine (LZ4 usually is extremely fast with a low but respectable compression ratio). I’ve set the swappiness to 100. I haven’t tried to set it higher, maybe it could help.
I usually run Firefox, Thunderbird, and GIMP on my machine. I may also have a few PDF files opened as well, plus Telegram, and in some cases, I have to start Chrome if a website doesn’t work on Firefox. When the problem occurs, the system freezes until Firefox eventually crashes.
MGLRU solves this issue, its min_ttl_ms option to be exact. Set it to 250 or more.
I’ve yet to experience the issue since I changed the ZRAM settings, but I’ve just set min_ttl_ms to 250. We’ll see how it goes.
Note to self: created file /etc/systemd/system/lru-gen-ttl.service:
To enable run:
Simpler setup is:
should that be
– – – – 250
instead of
– – – – 100
?
Even then it shouldn’t be *that* heavy. A few coworkers have TB an I’ve heard that it can be heavy, though I don’t know how much. I’ve used its ancestor Netscape Communicator in 1997, it would fit fine on my fresh new 16MB (MB not GB) machine, though I really didn’t like it and switched to elm then mutt once attachments became common. Since then development practices have heavily changed, and the required RAM to do the same thing have multiplied by 1000 and the performance dropped…
Once sylpheed then claws came along the old ways mostly died off for me.
I can’t remember what year I started using Linux but I believe it was somewhere around the initial release of SuSE for sale as I couldn’t download what I needed due to dialup constraints.
Definitely around 1996 though. I still remember picking up the big box in Circuit City of all places.
I spent some time investigating Firefox memory usage this weekend. I had some tabs at 4GB for a simple website. When restarting Firefox with a single window, memory usage started at 200 MB and crept higher fairly rapidly before topping at 4GB. I used Firefox Task Manager for monitoring. I disabled a few extensions, and the problem disappeared. It turned out that one adblocker plugin I use for testing caused the memory leak. zram with zstd already helped against crashes, but Firefox is now much more responsive as well…
Curious. Have you submitted an issue to the adblocker project repo (assuming a FOSS project?) about this? Would be pretty helpful if they could fix that leak.
Would you consider mentioning which adblocker it was?
It’s open-source, but there’s no “Issue” tab. I’d rather not mention the plugin publicly.
Don’t forget OOM Killer
What about it, are you saying don’t forget to turn it off or tune it?
After reading that page it’s an exercise in what ifs and in little to no way applies to typical computing on home PCs and SBC devices.
I do appreciate you sharing the link however.
Sure, but the point about OOM Killer is an interesting one – and one I’ve heard before in the Linux community. Some might not like the idea of the OS responding like Android but I think I’d rather have a system that still remains responsive than regularly run into lockup situations where my only option is to hard reboot.
Unfortunately my reply to @rooted got hit by the spam filter for including a hyperlink (which is weird, seeing as someone else provided the same hyperlink above and therefore the fact their comment is visible demonstrates it didn’t get hit by the spam filter…) but basically in the guide “Debunking zswap and zram myths” by Chris Down, the author explains that if you’re going to enable zram you should combine that with an OOM Killer, like Fedora does.
That’s because I don’t allow duplicate links.
Fair!
Priority is set to 100 by default but judging by years’ worth of testing/discussion across various online fora that’s way too low to the point of being practically useless and should probably be set to its maximum of 32767.
Also, isn’t the modern zram hotness zram-generator?
I was pushing zram (compcache) on Android back in 2009 and it’s used by default these days. I see no reason not to use it and zswap on most systems today.
Just wanted to note, I turned off oom-killer personally. I don’t want random processes killed because I hit some memory pressure.
And min_ttl_ms doesn’t do what some think, it doesn’t try to keep most recently used stuff in RAM more or less depending on how it’s set (the memory management ALWAYS tries to do that.) It also just kills processes if it can’t keep LRU in memory. I set it to 0 because, again, I’d rather not have random processes killed.
^ This is the one here…
Anecdotally, I encountered min_ttl_ms OOMing everything it could get it’s hands on just now.
It started with my running
du -hson a large subtree (no ionice), and my drives were thrashing as I was using them at the same time.Suddenly programs started OOMing, starting with my browser or plasmashell.
Looking at the log I saw mention of kswap0 being the OOM initiator.
I thought it odd that plasmashell also OOMd when I use cgroup to make sure it doesn’t swap.
Plasmashell automatically restarted, and I started to
swapoff -abecause memory was better now with a memory leak in plasmashell was now cleared after the restart, and the browser windows were OOMd.Except now swapoff just stopped before ending all swaps. I tried it again and plasmashell was still OOMd even though I probably had like 5GB available memory (
duwas still running).I had even been kicked completely out of my session twice while determining the cause.
Now that I set
min_ttl_msback to 0, I randuagain, and stressed my system with browsers, and have not had ANY OOM.Just one more thing, some oddity occurred with RAM being used vs available.
My system was still showing 8G, but no usage was climbing much over 3G and there was A LOT of IO going on.
I got real scared that a module died, and don’t think I’ve ever encountered a module die on me and still run.
When I finally could reboot, I ran memtest which came back clean (forgot I only had 1 module anyway).
Things have been going fine so far now without min_ttl_ms (apart from the unrelated plasmashell Shmem leak).
[ Has anyone here experience with cgroups, version2 and possibly optimized settings for lowering memory pressure from programs/processes?
stat -fc %T /sys/fs/cgroup
(tmpfs (vers. 1) | cgroup2fs (vers. 2))
memory.highmemory.maxmemory.lowmemory.swap.maxsystemd-run –user –scope -p MemoryMax=6G -p ManagedOOMMemoryPressure=kill firefox
(mainly above Kernel vers. (partly avail. 4.18) 5.8-5.10 ) (thx) ]
Yeah, even when I was “aware of” cgroup during the v1 period, I had only just started to get into it last year I guess.
My main use of it is for making sure kwin and plasmashell never swap out, so it remains performative.
I use
systemctl --user edit <service>to automatically put me in an editor for the override config (which also shows the existing config), alongside values I find inman systemd.directiveswhich shows EVERYTHING systemd has to offer and which man it’s in.