Коли в Linux починає не вистачати оперативної пам’яті, система підвисає, а програми закриваються. Постійний великий swap‑розділ не завжди доречний: він займає місце на диску і зношує SSD. Краще зробити swap «розумним»: створювати його автоматично лише під час дефіциту RAM і видаляти, коли пам’яті знову достатньо. Саме це ми й реалізуємо за допомогою bash скрипти + cron та systemd timers — чиста автоматизація задач для оптимізація продуктивності 😺

Основний How‑to: динамічний swap через systemd + Bash

Крок 1. Створіть керуючий скрипт

Скрипт аналізує вільну пам’ять і за потреби створює або видаляє swap‑файл. Працює обережно: перевіряє місце на диску, права доступу та поточне використання swap.

#!/usr/bin/env bash
set -euo pipefail

# Конфіг
LOW_MEM_PCT=10          # нижче — створюємо swap
HIGH_MEM_PCT=30         # вище — намагаємось прибрати наш swap
MIN_DISK_FREE_MB=2048   # мінімум вільного місця на /, щоб створювати swap
SWAP_SIZE_MB=2048       # розмір одного авто-swap (2 ГБ)
SWAPFILE_DIR=/swap.d
SWAPFILE="$SWAPFILE_DIR/auto-swapfile.swap"
SWAP_PRIORITY=5
MAX_USED_KB_FOR_REMOVE=65536  # якщо наш swap зайнятий <= 64 МБ — можна вимкнути
LOG_TAG="auto-swap"

if [[ $EUID -ne 0 ]]; then echo "Run as root"; exit 1; fi

mkdir -p "$SWAPFILE_DIR" && chmod 700 "$SWAPFILE_DIR"

mem_total_kb=$(awk '/MemTotal/ {print $2}' /proc/meminfo)
mem_avail_kb=$(awk '/MemAvailable/ {print $2}' /proc/meminfo)
mem_avail_pct=$(( mem_avail_kb * 100 / mem_total_kb ))

swap_total_kb=$(awk '/SwapTotal/ {print $2}' /proc/meminfo)
swap_free_kb=$(awk '/SwapFree/ {print $2}' /proc/meminfo)
swap_used_kb=$(( swap_total_kb - swap_free_kb ))

# Вільне місце на корені в КБ
root_free_kb=$(df -Pk / | awk 'NR==2{print $4}')
root_free_mb=$(( root_free_kb / 1024 ))

have_auto_swap() { swapon --noheadings --show=NAME | grep -q -- "$SWAPFILE"; }
used_kb_of_auto_swap() { awk -v f="$SWAPFILE" '$1==f {print $4}' /proc/swaps 2>/dev/null || echo 0; }

create_swap() {
  logger -t "$LOG_TAG" "Creating swapfile $SWAPFILE size ${SWAP_SIZE_MB}M"
  if ! fallocate -l ${SWAP_SIZE_MB}M "$SWAPFILE" 2>/dev/null; then
    dd if=/dev/zero of="$SWAPFILE" bs=1M count=$SWAP_SIZE_MB status=none
  fi
  chmod 600 "$SWAPFILE"
  mkswap "$SWAPFILE" >/dev/null
  swapon -p "$SWAP_PRIORITY" "$SWAPFILE"
  logger -t "$LOG_TAG" "Swapfile enabled"
}

remove_swap() {
  logger -t "$LOG_TAG" "Trying to remove swapfile $SWAPFILE"
  swapoff "$SWAPFILE"
  rm -f "$SWAPFILE"
  logger -t "$LOG_TAG" "Swapfile removed"
}

# Логіка прийняття рішень
if (( mem_avail_pct <= LOW_MEM_PCT )); then
  if ! have_auto_swap; then
    if (( root_free_mb >= MIN_DISK_FREE_MB + SWAP_SIZE_MB )); then
      create_swap
    else
      logger -t "$LOG_TAG" "Not enough disk space to create swap (free ${root_free_mb}MB)"
    fi
  fi
elif (( mem_avail_pct >= HIGH_MEM_PCT )); then
  if have_auto_swap; then
    used_kb=$(used_kb_of_auto_swap)
    if [[ -z "$used_kb" ]]; then used_kb=0; fi
    if (( used_kb <= MAX_USED_KB_FOR_REMOVE )); then
      remove_swap
    else
      logger -t "$LOG_TAG" "Swap in use (${used_kb}KB), postpone removal"
    fi
  fi
fi

Збережіть файл як:

sudo nano /usr/local/bin/auto-swap.sh
sudo chmod 700 /usr/local/bin/auto-swap.sh

Крок 2. Описуємо systemd service і timer

Щоб не плодити cron‑джоби, скористаємося cron та systemd timers саме у варіанті systemd: таймер раз на хвилину викликатиме наш сервіс.

# Сервіс
sudo tee /etc/systemd/system/auto-swap.service >/dev/null <<'EOF'
[Unit]
Description=Auto-manage swapfile on memory pressure

[Service]
Type=oneshot
ExecStart=/usr/local/bin/auto-swap.sh
Nice=10
EOF

# Таймер
sudo tee /etc/systemd/system/auto-swap.timer >/dev/null <<'EOF'
[Unit]
Description=Run auto-swap every minute

[Timer]
OnBootSec=2min
OnUnitActiveSec=1min
AccuracySec=10s
Unit=auto-swap.service

[Install]
WantedBy=timers.target
EOF

sudo systemctl daemon-reload
sudo systemctl enable --now auto-swap.timer
sudo systemctl status auto-swap.timer --no-pager

Крок 3. Перевірка роботи

Подивіться логи та активні swap‑пристрої:

journalctl -u auto-swap.service -n 50 --no-pager
swapon --show --bytes
free -h

Для штучного навантаження на RAM можна запустити важку збірку або відкрити багато вкладок у браузері. Також підійде короткий тест на Python (він виділить пам’ять і почекає):

python3 -c 'x=[bytearray(200*1024*1024) for _ in range(10)]; input()'

Альтернативні способи

  • zram/zswap: стискання у RAM замість запису на диск. На десктопах часто дає кращу чутливість. Пакети: zram-tools (Debian/Ubuntu), systemd-zram-generator (інші).
  • swapspace або systemd-swap: готові демони, що автоматично керують swap‑файлами. Зручні, якщо не хочете підтримувати власний скрипт.
  • Статичний swap‑файл фіксованого розміру: простіше, але без «самовидалення».

GUI-спосіб (через Cockpit)

Якщо ви любите графіку, веб‑консоль Cockpit допоможе керувати службами та дивитися пам’ять у реальному часі. Встановіть, увімкніть і відкрийте у браузері https://localhost:9090, далі розділ «Services → Timers» для керування авто‑таймером, а у «Metrics/Usage» — моніторинг RAM і swap ⚙️

sudo apt install -y cockpit
sudo systemctl enable --now cockpit.socket

FAQ

Чи безпечно часто створювати/видаляти swap на SSD?

Нормально у помірних межах, але інтенсивний swap зношує SSD. Якщо ви часто впираєтесь у RAM, спробуйте zram або додайте оперативну пам’ять.

fallocate завершився з помилкою

Деякі ФС (особливо з CoW, наприклад Btrfs без NOCOW) можуть не підтримувати ефективний fallocate для swap. Скрипт має резервний шлях через dd. На Btrfs рекомендується створити файл у каталозі з вимкненим CoW (chattr +C) і без стиснення.

swapoff каже, що пристрій зайнятий

Значить, наш swap ще використовується. Скрипт видаляє файл лише коли зайнято менше 64 МБ. Можете підвищити HIGH_MEM_PCT або MAX_USED_KB_FOR_REMOVE, або просто зачекати, поки сторінки повернуться у RAM.

Таймер не запускається

Перевірте статус і журнали:

systemctl status auto-swap.timer auto-swap.service --no-pager
journalctl -u auto-swap.service -b --no-pager
sudo systemctl daemon-reload
sudo systemctl restart auto-swap.timer

Права доступу Linux: mkswap відмовляє

Переконайтеся, що файл має права 600 і що ви запускаєте від root:

sudo chmod 600 /swap.d/auto-swapfile.swap
sudo swapon /swap.d/auto-swapfile.swap

Чи можна підкрутити swappiness?

Так, іноді корисно знизити агресивність свопінгу:

echo 40 | sudo tee /proc/sys/vm/swappiness
# постійно через sysctl
echo 'vm.swappiness=40' | sudo tee /etc/sysctl.d/99-swappiness.conf
sudo sysctl --system

Порада від Kernelka

Щоб не «стріляти собі в ногу», відрегулюйте пороги під вашу систему. На сервері з великим трафіком ставте нижчий LOW_MEM_PCT (5–8%), а на ноутбуці — вищий (10–15%). І тримайте відкритими інструменти моніторингу (htop, free, swapon) — так легше зрозуміти, коли спрацьовує автоматизація задач.

Підсумок

  • Ми додали розумний механізм створення/видалення swap‑файла при дефіциті RAM.
  • Використали чисті bash скрипти та systemd timer без зайвих залежностей.
  • Скрипт перевіряє права, місце на диску та безпечно зупиняє swap.
  • Показали альтернативи: zram/zswap, готові демони, статичний swap.
  • Налаштування гнучке: змінюйте пороги, розмір і пріоритет під ваші навантаження.