关于本文

国内经常有Linux爱好者经常会认为,装Linux系统只要是内存足够大,直接就不需要Swap分区。作者在这几年Linux使用过程中也证实了这个说法的错误,Swap分区在个人日常使用Linux设备上必须要有Swap,甚至必不可少!!

网上经常会有网友在讨论Swap对于现代Linux设备有没有用之类的话题,或者Swap分区到底要分区多大,在网上完炒的非常激烈。

参考:

Ask Ubuntu:kswapd0 is taking a lot of cpu

Arch Linux-Wiki:Swap

Swap分区作者建议桌个人面版系统的大小就是实际内存大小的2倍!但还有个国外的文章说Swap大小 = 实际内存 + √实际内存,试了一下,果然不幸!不幸的是休眠直接就恢复不了,估计这篇文章可能是要求服务器Swap分区大小计算方式吧,文章找不到了就不追究了…

不然会出现类似情形:

此时电脑异常卡顿

以上的情况出现在开发一公司项目时候,由于公司业务代码前后端均使用的微服务,且所有的服务启动起来至少需要16G内存,但我的Linux笔记本正好适合,刚开始就排除了内存不足,一致认为Linux是不是中了某种挖矿病毒,就刻意的搜索到了这样一篇文章kswapd0挖矿病毒的发现与清除,一看这个kswapd0程序的名字就知道,估计和Swap有关系,于是找资料查看此程序到底是个什么作用,在国外找到了一篇这样的文章kswapd0 is taking a lot of cpu最后才明白原来不是什么挖矿脚本,只是缺少了Swap分区导致,添加上Swap分区就解决了以上问题。

Swap

制作Swap分区前提:铸鼎建议作为个人使用的Linux笔记本,至少需要腾出内存分区大小相同的空闲磁盘分区,如果需要进行休眠,就需要内存两倍大小的空闲磁盘分区。

制作Swap文件:如果你满足不了以上的要求,建议制作Swap文件,Swap文件直接可以存储在你的磁盘的任何分区内,详细:Arch WiKi:Swap

查看是否已经存在Swap:

1
2
3
4004 ◯  swapon --show
NAME TYPE SIZE USED PRIO
/dev/sda4 partition 32G 0B -2

如果有,查看内存使用与Swap使用:

1
2
3
4
4006 ◯  free -h
total used free shared buff/cache available
内存: 15Gi 2.8Gi 9.5Gi 1.2Gi 3.2Gi 11Gi
交换: 31Gi 0B 31Gi

如果没有Swap,建议使用fdisk工具对你的磁盘进行分区,分区,切记!手下留情!!

分区成功后查看分区:

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
27
28
4008 ◯  sudo fdisk -l
Disk /dev/sda:476.94 GiB,512110190592 字节,1000215216 个扇区
磁盘型号:Netac SSD 512GB
单元:扇区 / 1 * 512 = 512 字节
扇区大小(逻辑/物理):512 字节 / 512 字节
I/O 大小(最小/最佳):512 字节 / 512 字节
磁盘标签类型:gpt
磁盘标识符:F759950E-A159-497B-BF34-95DCFDA09E79

设备 起点 末尾 扇区 大小 类型
/dev/sda1 2048 1026047 1024000 500M EFI 系统
/dev/sda2 1026048 1288191 262144 128M Microsoft 保留
/dev/sda3 1288192 527675391 526387200 251G Apple APFS
/dev/sda4 527675392 594784255 67108864 32G Linux 文件系统
/dev/sda5 594784256 1000215182 405430927 193.3G Linux 文件系统


Disk /dev/sdb:29.81 GiB,32010928128 字节,62521344 个扇区
磁盘型号:MassStorageClass
单元:扇区 / 1 * 512 = 512 字节
扇区大小(逻辑/物理):512 字节 / 512 字节
I/O 大小(最小/最佳):512 字节 / 512 字节
磁盘标签类型:dos
磁盘标识符:0xc1db6fd2

设备 启动 起点 末尾 扇区 大小 Id 类型
/dev/sdb1 * 2048 62455807 62453760 29.8G 7 HPFS/NTFS/exFAT
/dev/sdb2 62455808 62521343 65536 32M ef EFI (FAT-12/16/32)

我来解释一下我的磁盘以及分区情况,一共显示两个设备:

  • Disk /dev/sda:476.94 GiB

    • 设备分区:

      /dev/sda1 2048 1026047 1024000 500M EFI 系统
      /dev/sda2 1026048 1288191 262144 128M Microsoft 保留
      /dev/sda3 1288192 527675391 526387200 251G Apple APFS
      /dev/sda4 527675392 594784255 67108864 32G Linux 文件系统
      /dev/sda5 594784256 1000215182 405430927 193.3G Linux 文件系统

  • Disk /dev/sdb:29.81 GiB

    • 此设备分区:

      /dev/sdb1 * 2048 62455807 62453760 29.8G 7 HPFS/NTFS/exFAT
      /dev/sdb2 62455808 62521343 65536 32M ef EFI (FAT-12/16/32)

其中设备Disk /dev/sda:476.94 GiB就是我电脑的固态硬盘了,显示Swap分区就在那个32G的分区/dev/sda4上。

分区好Swap的分区,需要生成Swap分区的格式化:

1
2
# 其中的sdxy一定要根据你的分区定
mkswap /dev/sdxy

挂载(开启)Swap分区:

1
swapon /dev/sdxy

查看Swap分区UUID:

1
2
3
4
5
6
7
8
9
10
11
➜  ~ lsblk -f                
NAME FSTYPE FSVER LABEL UUID FSAVAIL FSUSE% MOUNTPOINTS
sda
├─sda1 vfat FAT32 1E45-250B 281.1M 44% /boot
├─sda2
├─sda3 apfs 89c01c70-c5dc-40e1-a69f-1280f4c02ad2
├─sda4 swap 1 f8c6db20-0b66-4928-925d-9c7dd462f67b [SWAP]
└─sda5 ext4 1.0 1e28352f-2cf3-400e-a3f7-7b5a6d5b2d9c 57.7G 64% /
sdb
├─sdb1 exfat 1.0 Ventoy 4E21-0000
└─sdb2 vfat FAT16 VTOYEFI C52C-B44F

将Swap分区的UUID填入fstab,每次开机挂载Swap分区:

1
UUID=device_UUID none swap defaults 0 0

需要编辑/etc/fstab文件,加进去上面的那行,保存即可在每次启动Linux激活Swap分区。

Arch系统休眠实现

一定要 Swap分区/Swap分区文件 大小为内存容量的2倍,不然当内存使用超过一半,就会出现休眠唤醒失败的可能。

参考:

Arch WiKi:Power management/Suspend and hibernate

Arch WiKi:Kernel parameters

In order to use hibernation, you need to create a swap partition or file. You will need to point the kernel to your swap using the resume= kernel parameter, which is configured via the boot loader. You will also need to configure the initramfs. This tells the kernel to attempt resuming from the specified swap in early userspace. These three steps are described in detail below.

为了使用休眠,你需要Swap分区或者Swap文件,将需要设置内核参数 resume= ,可以通过boot loader配置,你将需要配置intramfs,此文件会告诉内核企图恢复用户空间的内存数据Swap。以下三步将展示详细步骤:

Even if your swap partition is smaller than RAM, you still have a big chance of hibernating successfully. See “image_size” in the kernel documentation for information on the image_size sysfs(5) pseudo-file.

即使你的Swap分区小于RAM,你仍然有大几率休眠成功,有关镜像大小sysfs(5)伪文件的信息,请参阅内核文档中的“镜像大小”。(不建议这么做,但可以尝试)

配置intramfs

  • When an initramfs with the base hook is used, which is the default, the resume hook is required in /etc/mkinitcpio.conf. Whether by label or by UUID, the swap partition is referred to with a udev device node, so the resume hook must go after the udev hook.
  • 当使用带有base钩子的initramfs(默认),包含休眠Swap分区信息的钩子resume将被需要在/etc/mkinitcpio.conf文件中,无论使用分区的标签/UUID,这个Swap分区是udev看作设备的一个节点,所以你在编辑/etc/mkinitcpio.conf文件时,必须将resume钩子放在udev之后,这样才可以加载到 udev(Swap) => resume(原内存数据)。
  • When an initramfs with the systemd hook is used, a resume mechanism is already provided, and no further hooks need to be added.
1
HOOKS=(base udev autodetect keyboard modconf block filesystems resume fsck)

执行mkinitcpio -P

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
27
28
29
30
31
32
33
34
35
36
37
38
➜  ~ mkinitcpio -P
==> Building image from preset: /etc/mkinitcpio.d/linux-lts.preset: 'default'
-> -k /boot/vmlinuz-linux-lts -c /etc/mkinitcpio.conf -g /boot/initramfs-linux-lts.img
==> Starting build: 5.15.61-1-lts
-> Running build hook: [base]
-> Running build hook: [udev]
-> Running build hook: [autodetect]
-> Running build hook: [modconf]
-> Running build hook: [block]
==> WARNING: Possibly missing firmware for module: xhci_pci
-> Running build hook: [keyboard]
-> Running build hook: [filesystems]
-> Running build hook: [resume]
-> Running build hook: [fsck]
==> Generating module dependencies
==> Creating zstd-compressed initcpio image: /boot/initramfs-linux-lts.img
==> Image generation successful
==> Building image from preset: /etc/mkinitcpio.d/linux-lts.preset: 'fallback'
-> -k /boot/vmlinuz-linux-lts -c /etc/mkinitcpio.conf -g /boot/initramfs-linux-lts-fallback.img -S autodetect
==> Starting build: 5.15.61-1-lts
-> Running build hook: [base]
-> Running build hook: [udev]
-> Running build hook: [modconf]
-> Running build hook: [block]
# ==> WARNING: Possibly missing firmware for module: wd719x
# ==> WARNING: Possibly missing firmware for module: qla2xxx
# ==> WARNING: Possibly missing firmware for module: bfa
# ==> WARNING: Possibly missing firmware for module: qla1280
# ==> WARNING: Possibly missing firmware for module: qed
# ==> WARNING: Possibly missing firmware for module: aic94xx
# ==> WARNING: Possibly missing firmware for module: xhci_pci
-> Running build hook: [keyboard]
-> Running build hook: [filesystems]
-> Running build hook: [resume]
-> Running build hook: [fsck]
==> Generating module dependencies
==> Creating zstd-compressed initcpio image: /boot/initramfs-linux-lts-fallback.img
==> Image generation successful

铸鼎是两个内核,可以看到两个内核分别生成.preset: 'default'和.preset: ‘fallback’,原理请查看 Arch WiKi:mkinitcpio => Image_creation_and_activation

以上的WARNING处理就是解决大部分硬件的问题的关键,一定要重视这些WARNING!!尝试修复请看 Arch WiKi:mkinitcpio

添加内核参数

The kernel parameter resume=*swap_device* must be used. Any of the persistent block device naming methods can be used as *swap_device*. For example:

内核参数 resume=*swap_device*必须使用,任何持久块设备命名方法都可以用作交换设备。例如:

  • resume=UUID=4209c845-f495-4c43-8a03-5363dd433153
  • resume="PARTLABEL=Swap partition"

添加内核参数方法有分多,主要区别于你的Linux是哪个引导程序来引导启动的,比如说我的使用Grub(大部分Linux都是)引导启动:

  • To make the change persistent after reboot, you could manually edit /boot/grub/grub.cfg with the exact line from above, or if using grub-mkconfig:
  • 要使重新启动后的更改持续存在,可以使用上面的行或使用grub-mkconfig手动编辑/boot/grub/grub.cfg
  • Edit /etc/default/grub and append your kernel options between the quotes in the GRUB_CMDLINE_LINUX_DEFAULT line:
  • 编辑/etc/default/grub,并将内核选项附加到GRUB CMDLINE LINUX DEFAULT行的引号之间
1
GRUB_CMDLINE_LINUX_DEFAULT="resume=*swap_device*"

以下命令将/etc/default/grub生成到/boot/grub/grub.cfg

1
grub-mkconfig -o /boot/grub/grub.cfg

重启生效所有配置