针对 SSD 与大内存电脑的优化:内存虚拟硬盘的创建与使用

不管是 Windows 还是 Linux 都可以将内存中的一部分空间虚拟为硬盘空间来当成磁盘分区使用。Windows 上较多使用商业的内存虚拟硬盘软件,而 Linux 上则有原生的内存虚拟文件系统 TMPFS。

存在于内存中的这种文件系统读写速度很快,但是关机(或者仅仅是注销登录(logout))后其中的内容就会消失。**内存虚拟硬盘比较适合于存放系统/应用运行产生的临时文件,浏览器等应用的缓存文件等那些不需要保存下来的内容,或者是再次获取的代价很低的内容。**

但是前提是用户的电脑中有足够的物理内存。如果物理内存小,Windows 系统会开始使用虚拟内存,也就是存在硬盘上的一个文件。而 Linux 系统会开始使用 swap 交换分区,此时挂载于 TMPFS,也就是内存,中的 /tmp 也会受到影响,结果将是比直接放 /tmp 在磁盘中性能更差,当然也无助,甚至有害于 SSD 的健康。

根据个人使用经验,日常使用操作系统——不编译大型软件,不处理视频,不较多使用虚拟机——的时候,对于 Windows 来说一般不超过 4GB 而对于 Linux 来说一般不超过 3GB。此时如果还有剩余的物理内存,就可以考虑适当加以利用了。

这里的记录主要是针对新买的 ThinkPad T470s 上安装的 Linux 滚动发行版 openSUSE Tumbleweed,只有少部分关于 Windows 的配置。

Linux 中创建内存虚拟硬盘

Windows 上也有一些可以免费使用的商业 ramdisk 软件,比如 AMD Radeon RAMDisk 就允许免费用户创建 4GB 大小的内存盘。如果用户使用 AMD 的内存则可以创建 6GB 的内存虚拟硬盘。当然也有免费甚至开源的,如 ImDiskERAM。这里不关注 Windows 上的用法,只说 Linux 上的配置方法。

Linux 上配置内存虚拟硬盘非常简单。先在文件系统中创建一个挂载点(相当于「文件夹」),并将其设置为当前用户及用户组所有,例如,

$ sudo mkdir -p /data/zRamTmp
$ sudo chown $USER:$GROUPS /data/zRamTmp

这里 $USER 是一个系统变量,其值就是当前用户的用户名,也可以直接用用户名代替;而 $GROUPS 则可以用需要的用户组名或者号码来代替,也可以省略 :$GROUPS 这一部分仅设置用户所有权。

然后在 /etc/fstab 文件的末尾添加一个 TMPFS 类型的挂载项挂载到这个挂载点上就可以了,

$ sudo sh -c "echo 'tmpfs   /data/zRamTmp   tmpfs   rw,users,nodev,size=25%  0 0' >> /etc/fstab"

这里有几个挂载参数,rw 表示可读写,users 表示该磁盘的为「users」用户组所有(这是 SUSE 发行版中默认的常规用户的用户组),其它参数及含义可参考这里。而 size 参数则限制该内存盘的最大容量,以避免极端情况下造成内存耗尽,比如这里的 size=25% 表示最大用到总内存数量的 25%。还可以指定具体数值,比如 size=512M 表示 512MiB,size=2G 表示 2GiB 等。当然也可以连同 size 前面的 , 号一起删除,这样就表示不限制其大小。最后的两个数字都是内核名称描述符的参数,不能少。前一个代表 <dump>(ext2/3 文件系统备份标识,0 表示不备份),后一个代表 <fsck>(设置系统启动时检查文件系统的顺序,0 表示忽略)。

最后直接挂载该磁盘即可,

$ mount /data/zRamTmp

往后再启动系统的时候会自动挂载。

然后后查看 /data/zRamTmp 的类型,

$ df -h /data/zRamTmp
Filesystem      Size  Used Avail Use% Mounted on
tmpfs           5.9G  182M  5.7G   3% /data/zRamTmp

就可以知道它确实是正确的设置为 tmpfs 系统了。

虚拟内存与内存虚拟硬盘

有人会将虚拟内存(Windows 上的 pagefile 文件、Linux 上的 swap 交换分区也可以是个交换分区格式的文件)放到虚拟内存里。当前前提是物理内存很大。Windows 上这么用我不知道是否合适,但是至少 Linux 上是没有必要做这样的设置的。

在 Linux 上,用户可以配置系统使用交换分区 swap 的方式。通过设置下面的参数,交换分区基本上就用不上了。

先检查系统的 swappiness 参数,

$ cat /proc/sys/vm/swappiness
60

该参数默认设置的是 60,代表了一般的 Linux 系统使用 swap 的倾向性。将其改为 1,这样系统就会尽量避免使用 swap。可以先临时改成 1 看看效果,像下面这个命令行这样修改的设置重启系统后就失效了,

$ sudo sysctl vm.swappiness=1

如果实验没有问题,那就可以考虑固定该设置。修改 /etc/sysctl.conf 添加下面的参数到文件的最后,

vm.swappiness=1

也可以先看看该文件中有没有这个设置,

$ grep vm.swappiness /etc/sysctl.conf

如果输出为空,则说明之前没有设置该参数,那么直接将该参数 echo 到该文件的结尾即可,

$ sudo sh -c "echo 'vm.swappiness=1' >> /etc/sysctl.conf"

而如果这样还能用上 swap,那就说明物理内存实在是太小了,除非是出现了系统故障比如内存泄漏之类的。在这种情况下,设置 swap 到内存虚拟硬盘中只会增加系统的负担。所以最终还是不要将 swap 放到内存里比较好。

类似的,还可以设置另外一个控制系统回收内存中缓存的文件的倾向的参数 vm.vfs_cache_pressure。该参数默认是 100,建议改为 50。与上面的类似,

$ sudo sysctl vm.vfs_cache_pressure=50
$ grep vm.vfs_cache_pressure /etc/sysctl.conf
$ sudo sh -c "echo 'vm.vfs_cache_pressure=50' >> /etc/sysctl.conf"

将系统临时文件放到内存中

Windows 中可以通过修改用户和系统的 TEMP 以及 TMP 环境变量来实现(右键单击「我的电脑」选择「属性」->单击左侧边栏里的「高级系统设置」->在「高级」标签页里单击底部的「环境变量」->分别双击打开并修改上下两个框里的「TEMP」和「TMP」的值为内存虚拟硬盘中的文件夹路径即可;建议用户和系统的环境变量设置在不同的文件夹中,如 M:\zRamTmp\vmWin\user\TempM:\zRamTmp\vmWin\sys\Temp;TEMP 和 TMP 的值默认是一样的)。这似乎不是个好主意,因为有的应用不买这个帐,如果不是在本地磁盘中,它们就不工作,比如 Chrome 的自动更新等。

Linux,如 openSUSE Tumbleweed 上则将 /tmp 设为 TMPFS 类型即可。

openSUSE Tumbleweed 目前默认将 /tmp 挂载到根目录下的 /tmp 文件夹中,虽然 systemd 默认是在开机时通过 tmp.mount 服务将其挂载为 TMPFS 文件系统。

systemd 早已默认使用 TMPFS 文件系统来挂载 /tmp 临时文件夹。针对要不要将 tmp 放到 tmpfs 的问题,2012年3月的时候 openSUSE 社区经过一阵子讨论(邮件列表入口总结)后没有自动加载 tmp.mount 服务,而是将 /tmp 仍旧挂载到硬盘上的根分区,说是为了避免一些不兼容的应用/情形。再后来,2015年12月底,因为一个 VPN 服务导致的 tmp.mount 重新加载问题而干脆将 tmp.mount 从默认的 /usr/lib/systemd/system 移动到了 /usr/share/systemd/。所以此后即使用户主动执行,

$ sudo systemctl enable tmp.mount

或者,

$ sudo systemctl add-requires basic.target tmp.mount

也没用了,会提示找不到 tmp.mount 服务文件了。除非用户再将该文件复制到回到 /usr/lib/systemd/system 文件夹。

而且,tmp.mount 生效的**前提**是系统的 /etc/fstab 里中没有设置相应的 /tmp 挂载项。

好,解释完了一点背景,下面就是设置了。

在 openSUSE Tumbleweed 的安装过程中会自动产生一个加载 /tmp 的条目——至少在使用默认的 BTRFS 作为 root 分区 / 的文件系统格式的情况下是这样。该条目类似于(使用 UUID 标识磁盘分区的情况下),

UUID=[这里是一串代表磁盘分区 UUID 的字符] /tmp btrfs subvol=@/tmp 0 0

需要将这一条目注释掉——在其最前方加上 # 号,变成,

#UUID=[这里是一串代表磁盘分区 UUID 的字符] /tmp btrfs subvol=@/tmp 0 0

然后在 /etc/fstab 文件的最末尾加上自己的 /tmp 配置将其挂载到内存中,

tmpfs   /tmp            tmpfs   nodev,nosuid,uid=root,gid=root,mode=1777,size=25% 0 0

这里的 tmpfs 就表示使用 TMPFS 文件系统,而该文件系统就是在内存中虚拟一块硬盘出来。该硬盘最大会占物理内存容量的 25%(参考前面的解释)。

针对 VirtualBox 虚拟机的调整

VirtualBox 虚拟机在运行,还有关闭时(选择恢复快照初始状态时除外)会向硬盘写入大量的数据。运行过程中即使什么都不做,也可能有几百兆的写入量。而关闭时则根据使用过程中涉及到的数据量有所不同,但是一般情况下几个 GB 是有的。使用了 snapshot 快照功能的话,产生的数据量就更大,体现在正在使用的 snapshot 文件的体积会快速增长。此时如果关机后直接「删除」快照而不是「还原」快照的话,会因为合并数据到主磁盘文件而产生数 GB 的数据写入。这个似乎没有什么好的解决方案,只能尽量少用 VM,最起码也应该尽量在关闭 VM 的时候使用「恢复到快照初始状态」这个选项。这个可以在关闭 VM 直接点击窗口右上角的「X」,然后勾选「直接关闭」下面那一项。特别需要注意的是,关闭虚拟机时如果选择「保存当前状态」则会导致相当可观的磁盘写入。

使用虚拟机的一个主要方式就是配置好虚拟机之后就一般不再动其中的系统和配置,而是可以在每次用完之后就将其还原到当次开始用之前的状态。当然,需要保留的数据都是通过挂载「共享文件夹」的方式放在宿主机的物理磁盘中的。总之,当前 snapshot 快照磁盘快速增加的那些内容对我们来说是无用的。

鉴于上面说明的使用情景,我的用法就是将虚拟机快照目录更改到内存盘里。这么做有一个坏处就是,如果想保存当前的快照,就只能将其合并到该虚拟机的主磁盘中,而无法休眠之后下次从这里接着开始使用。而且,因为重启之后内存盘内容会被清空,那么即使是关闭虚拟机时选择复原后的那个 2MB 大小的快照也会消失。于是下次启动该虚拟机的时候会因为快照损坏而无法直接启动。但这不是大问题,只要再还原一下该快照就可以了。

另外,如果 VirtualBox 里的虚拟机是 Windows,还有可能会在运行时在后台自动对磁盘进行「整理碎片(defragmentation)」的操作。整理碎片对 SSD 来说是完全没有意义的,徒增磁盘写入量。所以应该在 VirtualBox 对应虚拟机的设置里找到「存储」里的那个虚拟磁盘,将其选项里的「固态硬盘」选项选中,这样客户机才能知道自己运行在 SSD 上。但是客户机时候会针对 SSD 进行优化就要看客户机的系统怎么处理了。很多优化设置可能还需要在客户机系统里进行调整,比如手动关闭「磁盘碎片整理」等,参见 https://forums.virtualbox.org/viewtopic.php?f=1&t=45055 以及 https://superuser.com/questions/74896/confirming-that-windows-7-is-using-ssd-optimizations 不过,运行时使用快照功能,并将快照移动到内存虚拟盘里面之后应该不需要再顾虑这个问题了。

针对应用的调整

更改临时文件和/或缓存文件的存储到内存盘

有人将整个 Linux 用户文件夹中的 .cache 都放到了内存虚拟硬盘中。我觉得这样太激进了,所以就挑一些感觉有必要的移过去。

一些应用程序在运行时会产生大量的临时文件和/或缓存文件,特别是 openSUSE 的系统升级应用 zypper,浏览器如 Firefox、Chrome 和 Opera。

zypper

将 zypper 的缓存文件放到内存盘有一个缺点是使用它的时候经常需要刷新软件源。

方法很简单,给 zypper 加上参数即可。平常使用的 zypper 改成 zypper --cache-dir /data/zRamTmp,如,

$ sudo zypper refresh

变成,

$ sudo zypper --cache-dir /data/zRamTmp refresh

为了省事,可以设置一个全局的指令别名给 zypper

alias zypper='zypper --cache-dir /data/zRamTmp'

为了省事,可以修改 zypper 的配置文件 /etc/zypp/zypp.conf 中的 {cachedir} 设置为内存盘的路径。注意:修改前最好先备份一份 zypp.conf 配置文件。

修改很简单,注意把下面的 \/data\/zRamTmp 这一部分按照自己的虚拟内存盘路径修改一下(这里 \ 是起转义作用的;汗,没找到合适的其它字符代替 /)。

$ sudo sed -i '/# cachedir = \/var\/cache\/zypp/a cachedir = \/data\/zRamTmp' /etc/zypp/zypp.conf

可能要重新启动系统才能生效。这样以后不管是 root 还是一般用户 sudo 运行 zypper 的时候就会自动使用新的路径做缓存。

Firefox

关于 Firefox 对 SSD 磁盘寿命的影响很多年前就已经有讨论了,但是大家对此看法不一,而且 Firefox 为了提升性能而不愿意妥协对磁盘缓存的利用。

Firefox 的磁盘缓存可以关闭(「设置」 -> 「高级」 -> 「网络」,勾选「缓存网络内容」下面的「覆盖自动缓存管理」,然后将下面的「限制缓存大小」改成 0)。

实际上,lifehacker 上的这篇文章就是这么介绍的。但是后来它更新了一个说明,表示 Mozilla 的一位开发人员对此表示了一些不同看法。例如,这样做会拖慢一些插件,比如 Adobe Reader,因为它需要将 PDF 文件缓存到磁盘中,否则就需要为其创建一个临时文件;内存缓存的容量要比磁盘的小(博主注:不知道大内存的情况如何);磁盘缓存可以在系统重启后保留因而效益更好等。

但是我觉得最好的方式是将 Firefox 磁盘缓存的位置改到内存盘中,比如前面创建的那个临时内存盘 /data/zRamTmp 中。默认的 Firefox 的磁盘缓存文件夹是在用户目录中,路径类似于 ~/.cache/mozilla/firefox/usermyname.default-1479389593198/cache2。修改方式为,

  1. 在 Firefox 地址栏输入 about:config 并回车;
  2. 根据提示确认接受风险并进入配置页面;
  3. 在地址栏下面的出现的新的搜索栏里输入 browser.cache.disk.parent_directory 查找,有的话可以双击修改;如果没有出现就右键单击新建一个 String 类型的设置,接着在提示输入名称的时候粘贴上这个字符串 browser.cache.disk.parent_directory,确认后下一步就是设置该参数的值;
  4. 将该参数的值改为/设置为内存盘的路径,比如 /data/zRamTmp/Firefox 然后确认保存,Firefox 会自动在该目录中创建一个名为 cache 的文件夹来使用。

另外还需要减少 Firefox 记录 session 的数据,这些数据是不在缓存目录中的。之前有人调查发现 Firefox 通过记录大量的运行时数据来实现崩溃时恢复之前的浏览状态等功能,但是要准确恢复崩溃前的状态就必须不断(默认是 15s 间隔)更新记录的 session 信息到 recovery.js 以及 cookie 文件中。如果用户开着 Firefox 并打开几个页面,然后把电脑放在那里什么也不干,都有可能因为 Firefox 的持续写入恢复数据而造成几十 GB 每天的写入量。这对我这种一不留神就开着几十个标签页搁在那里的用户来说简直就是噩梦。

当然只能在恢复的准确性和数据写入量之间取个折中了。我将默认的 15 秒改成了 25 分钟。修改方法与上面修改磁盘缓存目录类似,在 about:config 中查找关键词 browser.sessionstore.interval,双击修改其参数值,从默认的 15000 毫秒改成 1500000 毫秒。如果不需要这个功能,也可以直接关闭:双击修改 browser.sessionstore.resume_from_crash 参数的值为 False

还有更极端的做法就是直接将 Firefox 的整个用户档都放到内存中。使用脚本在开机时载入,在关机时重新存到磁盘上,或者是设置一定的间隔时间将更新保存到磁盘。但是我觉得必要性不大。

估计跟 Firefox 类似的应用还有不少,得根据自己的使用情况慢慢发现了。针对 Firefox 的调优还有很多其它与 SSD 无关的技巧,可以参考这里

Chrome / Chromium

Chrome 没有提供设置缓存文件夹路径的设置,但是可以在其启动项上加参数来实现

Linux 上 Chrome / Chromium 默认的缓存文件夹分别在 ~/.cache/google-chrome~/.cache/chromium 中。如果在启动 时候加上参数 --user-data-dir=/data/zRamTmp 就会将缓存放到 /data/zRamTmp 文件夹下。

以 openSUSE Tumbleweed 上 KDE 桌面里的 Chrome 为例,

  1. 在启动 Chrome 的桌面图标、开始菜单图标和/或任务栏快速启动图标上右键单击,然后选择「属性」或「编辑应用」;
  2. 在弹出的窗口中选择「应用」标签页,将其中「命令 (Command)」后面的 `%u 参数之前加上 --user-data-dir=/data/zRamTmp 即可(注意在不同的参数之间留个空格)。

Windows 系统里的 Chrome 的设置与此类似。这样做的缺点似乎是 Chrome 的自动升级功能会报错(还未确认)。

qBittorent

将 qBittorent 或其它下载软件的临时文件夹,甚至是存储文件夹放到虚拟内存盘中。因为有时候没下完可能就不想继续下载了,又或者下载的是压缩文件需要解压之后才能用,等等。

openSUSE 系统设置

系统事件日志 journald

如果不需要系统日志记录,可以关闭 systemd-journald。默认情况下,openSUSE 上的 journald 会每 30 秒将系统事件记入日志,这也会造成不少的磁盘写入,即便是系统处于闲置状态。不过写入量应该不是太大(我不知道怎么测试)。关闭 systemd-journald 只需要在其配置文件 /etc/systemd/journald.conf 中将日志记录目录设置为 none (将 #Storage= 开头的那行改为 Storage=none)然后重启该服务,

$ sudo systemctl restart systemd-journald

Trim

检查是否支持 Trim。先检查自动 Trim 功能是否开启

$ systemctl status fstrim.timer
● fstrim.timer - Discard unused blocks once a week
Loaded: loaded (/usr/lib/systemd/system/fstrim.timer; enabled; vendor preset: enabled)
Active: active (waiting) since Thu 2017-03-30 08:32:15 BST; 3h 11min ago
Docs: man:fstrim

这样的话就表示系统已经开启了每周自动 Trim 一次。

查看应用的磁盘写入状态

最后,做好了一般的调整之后,还可以再根据自己的使用习惯观察一下。可以使用 iotop 来查看各种进程的磁盘写入情况。openSUSE Tumbleweed 的官方源中就有 iotop。检查可以使用这个指令,

$ sudo iotop -oPak -d 1

使用键盘左右方向键切换排序的列,Ctrl+c 退出。不过要自己排除那些写入虚拟内存盘或者外接存储设备的数据量。

启用 BtrFS 系统的 reflink

~/.bashrc 中最后面加入下面一行,

alias cp='cp --reflink=auto'

Windows 系统设置

刚好看到有篇文章总结在 Windows 中优化 SSD 使用的文章(10 Tips optimisation SSD on Windows 7),挺全面的。虽然是针对 Windows 7 的但是大部分对 Windows 10 依旧有效。摘要如下,

  1. 确保系统运行在 AHCI 模式下(BIOS 设置);
  2. 检查 Trim 是否启用;
  3. 检查 SSD 格式化时候的分区是否实现了 4k 对齐;
  4. 禁用磁盘索引(在磁盘分区上右键单击并选择「属性」,然后将「常规」标签页最下面的「允许索引文件」那个选项去掉(默认是勾选的))。
  5. 关闭磁盘碎片整理;
  6. 关闭系统还原(右键单击「我的电脑」,选择「属性」,然后单击「系统保护」选项页,将里面所有 SSD 分区都设置为关闭);
  7. 禁用虚拟内存(Paging Files);
  8. 禁用休眠;
  9. 禁用 Prefetch 和 Superfetch;
  10. 禁用图形启动(因为 SSD 太快了,那个启动界面图形纯粹是浪费时间)。

这里不再过多展开了,随便一搜就能找到很多图文并茂的操作步骤介绍。

更新:做个记录。今天是10月12日,过去快半年了。我的 SSD 写入才刚刚过 1GB,读取也只比写入高了约 30GB。看来我虽然用电脑很多,但是用磁盘很少。

如果有朋友看了这篇记录,还请补充一些我没有发现的技巧 :-)©

本文发表于水景一页。永久链接:<https://cnzhx.net/blog/optimisation-on-ssd-and-large-ram/>。转载请保留此信息及相应链接。

3 条关于 “针对 SSD 与大内存电脑的优化:内存虚拟硬盘的创建与使用” 的评论

  1. 在我的WIN7上面用了2G内存模拟硬盘 用来下载和放浏览器的缓存文件,减少对固态硬盘的写入,嘿嘿。

    • 做优化的效果的确是很明显的,而且一般使用情况下 2GB 也差不多够了。做了这些优化之后,我一个半月的写入量还不到 1TB。不过现在的确是很少涉及到大文件的读写了,可能是有意避免的结果,很多感觉没必要的东西就不存了,直接在内存盘中就处理完了。

  2. 引用通告: 在 T470s 上折腾 Linux 滚动发行版 openSUSE Tumbleweed 记录汇总 | 水景一页

时间过去太久,评论已关闭。
如果您有话要说,请到讨论区留言并给出此文章链接。
谢谢您的理解 :-)