幫助中心

伺服器、網路和帳戶的分步教程。

Linux 伺服器

512MB / 1GB 小記憶體 Linux VPS 最佳化:zram、Swap、journald 限制與精簡系統服務

512MB / 1GB 小記憶體 Linux VPS 最佳化:zram、Swap、journald 限制與精簡系統服務

想讓 512 MB 或 1 GB 記憶體的 Linux VPS 跑得順暢,請先測量記憶體到底被誰佔用,再在小 swap 檔案之上加一層記憶體壓縮交換(zram),限制 systemd 日誌的大小,並關閉伺服器用不到的服務。本文在 Debian 12/13 與 Ubuntu 22.04/24.04 上逐步演示,標註 Rocky Linux 與 AlmaLinux 的差異,並說明記憶體仍然耗盡時如何解讀 OOM killer 的日誌。

JUSTG 雲伺服器 mini 套餐為 512 MB 記憶體、10 GB SSD,01 套餐為 1 GB 記憶體、20 GB SSD。硬碟容量不大,swap 和日誌也要控制在合理範圍。以下命令請以 root 執行。

步驟 1:先測量,再動手

先找出真正佔用記憶體的程序,才能對症下藥。

free -h
ps -eo pid,user,rss,comm --sort=-rss | head -n 15   # RSS in KB, biggest first
systemd-cgtop -m -n 1                                # memory per service
cat /proc/pressure/memory                            # memory pressure (PSI)

ps 列出佔用最大的程序,systemd-cgtop 則按服務彙總記憶體,當一個服務有很多工作程序時更直觀。/proc/pressure/memory 中的 avg60 如果長期高於 10 左右,說明程序經常在等待記憶體。(Rocky/AlmaLinux 預設關閉 PSI,需要以 psi=1 核心引數啟動才能使用。)

RSS 會把共享庫完整地算進每個程序,所以加總後看起來比實際更多。smem 顯示的 PSS 會把共享記憶體合理地分攤到各個程序:

apt install smem            # Rocky / AlmaLinux: from EPEL
smem -tk -s pss -r | head -n 15

步驟 2:正確解讀 free -h:看 available,而不是 free

               total        used        free      shared  buff/cache   available
Mem:           961Mi       402Mi        74Mi       5.0Mi       484Mi       410Mi
Swap:          1.0Gi        12Mi       1.0Gi

free 數值很小是正常現象。Linux 會把空閒記憶體用作頁面快取(buff/cache)來快取檔案,程式需要時會立即釋放。真正要看的是 available:估算新任務在不使用 swap 的情況下還能拿到多少記憶體。上例中“空閒”只有 74 MB,但可用記憶體有 410 MB,伺服器完全正常。只有當 available 長期低於記憶體的 10% 左右、swap 用量又持續上升時,才需要擔心。

步驟 3:啟用 zram(記憶體壓縮交換)

zram 會在記憶體中建立一個交換裝置,以壓縮形式存放記憶體頁,體積通常只有原來的 1/2 到 1/3。交換到 zram 比交換到硬碟快得多,是給小套餐“擴容”非常有效的方法,代價是壓縮需要少量 CPU。

確認核心支援 zram

modprobe zram && echo "zram is available"
swapon --show

如果 modprobe 提示 Module zram not found,說明核心編譯時沒有包含 zram(部分精簡版雲核心如此)。請直接跳到步驟 4,只使用 swap 檔案。

方式 A:zram-tools(Debian、Ubuntu 22.04 與 24.04)

apt install zram-tools
cp /etc/default/zramswap /etc/default/zramswap.bak
cat > /etc/default/zramswap <<'EOF'
ALGO=zstd
PERCENT=50
PRIORITY=100
EOF
systemctl restart zramswap
zramctl
swapon --show

PERCENT=50 把 zram 裝置大小設為記憶體的一半(指未壓縮的容量),實際佔用的記憶體是壓縮後的大小。PRIORITY=100 讓核心優先使用 zram,再使用硬碟上的 swap。

方式 B:systemd zram-generator(Debian 12/13、Ubuntu 24.04、Rocky/AlmaLinux 9)

apt install systemd-zram-generator      # Rocky / AlmaLinux 9: dnf install zram-generator
cat > /etc/systemd/zram-generator.conf <<'EOF'
[zram0]
zram-size = min(ram / 2, 2048)
compression-algorithm = zstd
swap-priority = 100
EOF
systemctl daemon-reload
systemctl start [email protected]
zramctl

在 Rocky/AlmaLinux 上,如果 dnf 找不到該軟體包,請先啟用 EPEL(dnf install epel-release)。

兩種方式只能選一種:同時使用 zram-tools 和 zram-generator 會建立互相沖突的裝置。如果系統不接受 zstd,請改用 lz4,它在負載較高的單核套餐上也更快。

步驟 4:保留小 swap 檔案作後備,並調整 swappiness

zram 位於記憶體中,所以硬碟上的小 swap 檔案仍有價值,可作為最後的後備:這幾檔套餐用 512 MB–1 GB 就夠了。建立方法、寫入 fstab 和調整大小,請按Linux VPS 新增 Swap 交換空間教程逐步操作。swap 檔案的預設優先順序低於 zram 裝置,只有 zram 用滿後才會用到它。

啟用 zram 後,請調高 vm.swappiness:把記憶體頁壓縮換進 zram,比丟棄檔案快取再從硬碟重新讀取更划算。vm.page-cluster = 0 讓核心不再一次預讀多個 swap 頁,這種預讀只對硬碟有幫助。

cat > /etc/sysctl.d/99-zram.conf <<'EOF'
vm.swappiness = 100
vm.page-cluster = 0
EOF
sysctl --system
sysctl vm.swappiness vm.vfs_cache_pressure

/etc/sysctl.d/ 下的檔案按字母順序讀取,因此 99-zram.conf 會覆蓋 swap 教程中 99-swap.conf 設定的 vm.swappiness=10。沒有 zram 時請保持 10。該教程中的 vm.vfs_cache_pressure=50 可以保留;但千萬不要設為 0,否則核心將永遠不回收檔案系統後設資料。

步驟 5:限制 journald 日誌

systemd 日誌存放在硬碟的 /var/log/journal;如果日誌不是持久化儲存,則存放在 /run/log/journal。/run 是 tmpfs,也就是說這份日誌佔用的是記憶體。請同時限制兩者:

journalctl --disk-usage
mkdir -p /etc/systemd/journald.conf.d
cat > /etc/systemd/journald.conf.d/size.conf <<'EOF'
[Journal]
SystemMaxUse=100M
RuntimeMaxUse=20M
MaxRetentionSec=1month
EOF
systemctl restart systemd-journald
journalctl --vacuum-size=100M
journalctl --disk-usage

SystemMaxUse 限制硬碟上的日誌,RuntimeMaxUse 限制記憶體中的日誌,MaxRetentionSec 會刪除超過一個月的記錄。Ubuntu 上的 rsyslog 還會把同樣的訊息寫入 /var/log/syslog;該檔案由 logrotate 輪轉,一般保留即可。

步驟 6:關閉伺服器用不到的服務

停用任何服務之前,先看清楚正在執行什麼,並且只關閉你能確認用途的服務:

systemctl list-units --type=service --state=running
systemctl status multipathd --no-pager                  # what is it and what started it?
systemctl list-dependencies --reverse multipathd.service  # does anything need it?
服務常見於可以關閉的情況
snapdUbuntusnap list 中沒有你在用的 snap(見下文)
multipathdUbuntu Servermultipath -ll 沒有輸出,VPS 上通常如此
ModemManager部分 Ubuntu 映象VPS 上一律可以關閉:根本沒有調變解調器
tunedRocky / AlmaLinux可選,能省下少量記憶體;拿不準就保留
# Ubuntu: multipath storage daemon (not needed without SAN/multipath disks)
multipath -ll                       # no output = not in use
systemctl disable --now multipathd.service multipathd.socket

# Modem manager - a VPS has no modem
systemctl disable --now ModemManager

# Undo at any time:
systemctl enable --now multipathd.service multipathd.socket

snapd 會佔用幾十 MB 記憶體,併為每個 snap 掛載一個 loop 裝置。解除安裝它會同時刪除所有已安裝的 snap 及其資料,所以請先檢查 snap list。例如 certbot 是用 snap 安裝的,請先改用 apt 安裝 certbot,再解除安裝 snapd。pin 檔案可以防止 apt 以後又把 snapd 當作依賴裝回來。

snap list                           # what is installed as a snap?
apt purge snapd
cat > /etc/apt/preferences.d/no-snapd.pref <<'EOF'
Package: snapd
Pin: release a=*
Pin-Priority: -10
EOF
以下服務不要關閉:ssh/sshd、systemd 自身的服務(systemd-journald、systemd-logind、systemd-networkd、systemd-resolved)、networking 或 NetworkManager、cron、時間同步(chrony 或 systemd-timesyncd)以及防火牆(ufw、firewalld、nftables)。如果裝有 qemu-guest-agent 和 cloud-init,也請保留:平臺可能依賴它們,而且伺服器啟動後它們幾乎不佔記憶體。請用 disable 而不是 mask,方便日後重新啟用。

步驟 7:把自動更新安排在低峰時段

不要關閉 unattended-upgrades:安全更新比幾 MB 記憶體重要得多。記憶體高峰來自 apt 執行本身,所以把它安排到空閒時段即可。預設情況下,apt 會在 12 小時視窗內的隨機時間下載更新,並在約 06:00–07:00 之間安裝;以下 drop-in 配置把下載改到伺服器時間 04:00、安裝改到 04:30(可用 timedatectl 檢視伺服器時區):

mkdir -p /etc/systemd/system/apt-daily.timer.d /etc/systemd/system/apt-daily-upgrade.timer.d
cat > /etc/systemd/system/apt-daily.timer.d/override.conf <<'EOF'
[Timer]
OnCalendar=
OnCalendar=*-*-* 04:00
RandomizedDelaySec=15m
EOF
cat > /etc/systemd/system/apt-daily-upgrade.timer.d/override.conf <<'EOF'
[Timer]
OnCalendar=
OnCalendar=*-*-* 04:30
RandomizedDelaySec=15m
EOF
systemctl daemon-reload
systemctl list-timers 'apt-*'

Rocky/AlmaLinux 如果使用 dnf-automatic,請用同樣的方法修改 dnf-automatic.timer。

步驟 8:選擇更輕量的軟體

  • 保留 OpenSSH。它空閒時只佔幾 MB。Dropbear 等替代品省不了多少記憶體,缺少部分安全功能,發行版的更新也更少,不值得冒這個險。
  • 優先使用 nginx,而不是 Apache + mod_php。在 Apache 的 prefork 模式下,每個子程序都帶著完整的 PHP 直譯器。nginx + PHP-FPM,或至少 Apache 的 mpm_event + PHP-FPM,記憶體佔用要少得多。
  • PHP-FPM 使用 pm = ondemand。有請求時才啟動 worker,空閒一段時間後自動退出,而不是一直駐留在記憶體裡。
  • 按套餐調整資料庫。MySQL 與 MariaDB 的預設值是按更大記憶體設計的:請調小緩衝池和 max_connections,並關閉 performance_schema。
; /etc/php/8.2/fpm/pool.d/www.conf  (Rocky / AlmaLinux: /etc/php-fpm.d/www.conf)
pm = ondemand
pm.max_children = 5
pm.process_idle_timeout = 10s
pm.max_requests = 500

路徑中的 PHP 版本因系統而異:Debian 12 為 8.2,Debian 13 為 8.4,Ubuntu 22.04 為 8.1,Ubuntu 24.04 為 8.3。pm.max_children 的取值是能分給 PHP 的記憶體除以單個 worker 的平均大小,例如 200 MB / 40 MB = 5。先測量大小,再檢查配置並重新載入:

# Average size of a PHP-FPM process
ps -eo rss,comm | awk '/php-fpm/ {s+=$1; n++} END {if (n) printf "%d processes, average %.0f MB\n", n, s/n/1024}'
php-fpm8.2 -t && systemctl reload php8.2-fpm    # Rocky / AlmaLinux: php-fpm -t && systemctl reload php-fpm

步驟 9:瞭解 OOM killer 並找出 OOM 事件

記憶體和 swap 都用盡時,核心的 OOM killer 會終止一個程序來保住整個系統,通常是 oom_score 最高、一般也就是佔用最大的那個。服務“莫名其妙”地重啟、資料庫突然消失,往往都是被 OOM 殺掉了。請在核心日誌中搜尋:

journalctl -k | grep -i -E 'out of memory|oom-kill|killed process'
dmesg -T | grep -i -E 'out of memory|killed process'
journalctl -k -b -1 | grep -i 'killed process'     # previous boot (persistent journal only)

典型的日誌如下:

Out of memory: Killed process 812 (mariadbd) total-vm:1325400kB, anon-rss:301220kB, file-rss:0kB, shmem-rss:0kB, UID:106

其中寫明瞭程序名稱和它當時佔用的記憶體(anon-rss,單位 kB)。如果同一個服務反覆被殺,請調小它的配置、新增 swap 或 zram,或按步驟 10 為它設定上限。在 Ubuntu 上還請檢查 systemctl status systemd-oomd:該服務處於執行狀態時,可能會在核心出手之前,因記憶體壓力直接停止整個服務。

步驟 10:用 systemd MemoryMax 限制吃記憶體的服務

給單個服務設定記憶體上限,可以保護伺服器上的其他服務:如果 PHP-FPM 發生記憶體洩漏,被限制的只有 PHP-FPM,SSH 和資料庫照常執行。MemoryHigh 是軟限制,超過後核心會讓該服務變慢並回收其記憶體;MemoryMax 是硬限制,達到後 OOM killer 只在該服務內部動手。

stat -fc %T /sys/fs/cgroup          # cgroup2fs = cgroup v2 (required)
mkdir -p /etc/systemd/system/php8.2-fpm.service.d
cat > /etc/systemd/system/php8.2-fpm.service.d/memory.conf <<'EOF'
[Service]
MemoryHigh=250M
MemoryMax=300M
# A killed worker is replaced by the master instead of stopping the service
OOMPolicy=continue
Restart=on-failure
EOF
systemctl daemon-reload
systemctl restart php8.2-fpm
systemctl show php8.2-fpm -p MemoryHigh -p MemoryMax -p MemoryCurrent

Debian 12/13、Ubuntu 22.04/24.04 與 Rocky/AlmaLinux 9 預設使用 cgroup v2。在 Rocky/AlmaLinux 8 等使用 cgroup v1 的舊系統上,請改用 MemoryLimit=;MemoryHigh 只在 v2 下有效。不要給資料庫本身設定硬上限:突然被殺會導致崩潰恢復,應該調整它自身的引數。

步驟 11:判斷何時該升級套餐

最佳化適用於偶發的記憶體高峰。如果 available 一直很低、swap 始終處於繁忙狀態,vmstat 1 10 顯示持續的換入換出(si/so),說明業務本身就需要更多記憶體。JUSTG 雲伺服器可以在服務頁面升級套餐,詳見VPS 升級記憶體、SSD 硬碟或 IP 教程。

常見問題

zram 比 swap 檔案更好嗎?

速度上是的:它以記憶體速度工作,不產生硬碟 I/O。但它受記憶體大小限制,所以小套餐的最佳方案是兩者並用:高優先順序的 zram 負責日常交換,小 swap 檔案作為最後的後備。

zram 會佔用很多 CPU 嗎?

壓縮需要一些 CPU,通常很少。如果單核套餐上的伺服器一直在往 zram 交換,請改用 lz4 並減輕負載,因為持續交換說明記憶體確實不夠。

512 MB 的 mini 套餐能跑 Docker 嗎?

跑一兩個小應用的容器可以,但 Docker 守護程序和容器執行時本身也要佔用記憶體。請為每個容器設定記憶體上限,同時啟用 zram 和 swap;容器較多時,建議選擇 1 GB 及以上的套餐。

如果服務仍不斷被殺、又找不到原因,請至 https://www.justg.com/submitticket.php 提交工單,並附上伺服器 IP 以及 free -h 和 journalctl -k | grep -i oom 的輸出。JUSTG 提供 7×24 小時 AI 客服(工單),需要人工處理的問題會由工程師跟進。

這篇文章有幫助嗎?
幫助中心
Linux 伺服器 Linux SSH 金鑰登入教程:設定 ed25519 金鑰並禁用密碼登入 只要伺服器有公網 IPv4,上線幾分鐘內就會遇到 SSH 暴力破解機器人,而密碼登入正是它們的首要目標。本文說明如何用較新的 ed25519 金鑰完成 Linux SSH 金鑰登入,再禁用 SSH 密碼登入,全程避免把自己鎖在門外。步驟適用於 Debian… Linux 伺服器 Linux VPS 修改 SSH 連接埠與 root 密碼教程(安全不斷線) 把 SSH 從 22 連接埠移走雖然擋不住有心的攻擊者,卻能讓日誌裡大部分自動掃描消失;而任何新伺服器的第一件事,就是換一組新的 root 密碼。本文說明如何在 Linux VPS 修改 SSH 連接埠與 root 密碼且不斷線:修改 sshd_config、在 Rocky… Linux 伺服器 Linux 防火牆設定教程:VPS 使用 UFW 與 firewalld(含 IPv6) 新安裝的 Linux 伺服器,任何服務開啟的連接埠都會直接對外響應,因此主機防火牆是最先要設定的專案之一。本文說明如何在 Debian / Ubuntu 用 UFW 設定 Linux 防火牆,以及在 CentOS、Rocky Linux、AlmaLinux 使用… Linux 伺服器 Linux VPS 新增 Swap 交換空間教程(適合 512MB / 1GB 小記憶體套餐) 在 512 MB 或 1 GB 的雲伺服器上,資料庫、PHP-FPM 加上一次軟體包更新,很容易在同一時間用光記憶體。這時核心的 OOM killer 會強制終止程序,最常被犧牲的就是 MySQL 或 MariaDB。在 Linux VPS 新增 Swap… Linux 伺服器 Linux 硬碟空間已滿怎麼辦?VPS 找出並釋放磁碟空間教程 “No space left on device”幾乎會讓伺服器上所有東西出問題:資料庫無法寫入、網站返回錯誤、軟體包更新失敗,有時甚至無法正常登入。本文一步步說明如何排除 Linux 硬碟空間已滿:先確認是資料塊還是 inode 用完,再用 du 與 ncdu…
AlipayUnionPayVISAMastercardPayPalUSDTstripe