2026/8/13 13:30:40

Ubuntu内存管理与Swap配置优化:从安装规划到内核调优实战

Ubuntu内存管理与Swap配置优化:从安装规划到内核调优实战 1. 从一次“内存不足”的报错说起那天下午我正在Ubuntu服务器上编译一个大型的C项目make -j8命令跑得正欢终端突然就卡住了。紧接着熟悉的“Killed”信息弹了出来。不用说肯定是内存不够系统里的OOM Killer内存溢出杀手把我的编译进程给干掉了。这已经不是第一次了。我这台老伙计当初安装系统时本着“够用就行”的原则只给了8GB的物理内存虚拟内存Swap更是随手设了个2GB。平时跑跑Web服务、写写代码还行一旦遇到内存消耗大户立马就现了原形。我相信很多朋友都遇到过类似的情况。无论是新装Ubuntu时对内存分区举棋不定还是用了一段时间后发现“内存怎么老是不够用”本质上都是对Linux内存管理机制和Ubuntu安装时的存储规划理解不够深入。网上教程很多但大多只给命令不说原理只讲操作不谈场景。结果就是照猫画虎做完问题可能暂时缓解但根本的瓶颈还在或者甚至引入了新的性能问题。今天我就结合自己多次给服务器和工作站安装、调配Ubuntu的经验把“安装”和“内存分配”这两件看似独立、实则紧密相关的事情串起来讲透。我们不仅要解决“怎么装”和“怎么调”的问题更要弄明白“为什么这么装”以及“调了之后会发生什么”。无论是准备在新硬盘上安装Ubuntu的新手还是想优化现有系统内存性能的老鸟这篇文章都能给你一套清晰、可操作、有深度的方案。2. 安装Ubuntu时的内存规划不止是分一个区那么简单很多人认为安装系统就是点“下一步”分区方案用默认的就好。但对于追求性能和稳定性的用户尤其是开发者或打算将Ubuntu作为主力系统的人安装时的存储规划是决定后续内存体验的基石。这里的内存不仅仅指物理内存RAM更关键的是交换空间Swap的配置。2.1 物理内存与交换空间理解它们的共生关系物理内存是你插在主板上的内存条速度快但容量有限且断电数据丢失。交换空间则是硬盘SSD或HDD上划出的一块特殊区域用来存放暂时不用的内存数据。当物理内存吃紧时系统会把一部分闲置数据“交换”到硬盘上腾出物理内存给更活跃的程序使用。这个过程听起来很美但有个致命问题硬盘速度远慢于内存。即便是NVMe SSD其速度与内存相比也有数量级的差距。一旦发生频繁的“交换”称为Swap Thrashing系统就会变得极其卡顿因为CPU大部分时间都在等待硬盘I/O。所以我们所有优化策略的核心思想是尽可能让程序和数据待在物理内存里减少对交换空间的访问。交换空间是“安全网”而不是“扩展内存”。2.2 安装时Swap分区设置的黄金法则与过时建议的对比你在网上可能看到过各种关于Swap大小的“经验公式”比如“Swap大小等于物理内存”、“Swap是物理内存的2倍”等等。这些规则在内存以MB、GB计价的机械硬盘时代或许有其道理但在今天2023年及以后尤其是对于配备了8GB及以上内存的普通用户和开发者需要重新审视。1. 休眠Hibernate支持这是Swap分区必须存在的首要理由现代操作系统包括Ubuntu的休眠功能其本质是将当前物理内存中的所有数据完整地写入交换空间然后关机。下次开机时再从交换空间读回数据恢复到休眠前的状态。因此如果你需要休眠功能交换空间的大小必须至少等于你的物理内存总量。对于16GB内存的笔记本如果你想休眠Swap至少需要16GB。2. 内存溢出OOM防护这是Swap的核心作用即使你不休眠Swap也至关重要。没有Swap当物理内存耗尽时Linux内核的OOM Killer会直接选择并杀死某个进程来释放内存。这可能导致关键服务崩溃、数据丢失。而有Swap系统会先将一些不活跃的内存页换出为紧急情况提供一个缓冲地带虽然会变慢但给了你干预和解决问题的机会。3. 基于使用场景的现代Swap配置建议结合上述两点我的建议如下桌面用户内存≥8GB且不需要休眠物理内存 ≤ 8GB设置2GB - 4GB的Swap。这是一个合理的缓冲区间。物理内存 ≥ 16GB可以设置一个较小的Swap例如2GB - 4GB甚至可以考虑使用Swap文件代替分区更灵活。对于32GB及以上内存的机器如果确信工作负载不会用满内存理论上可以不要Swap但极其不推荐。因为某些系统管理或内核操作可能仍会用到少量Swap。桌面/开发用户需要休眠功能Swap大小 ≥ 物理内存总量。这是硬性要求。例如16GB内存Swap至少16GB。服务器服务器通常禁用休眠为了快速启动和恢复服务。Swap的主要目的是防止OOM导致服务崩溃。建议设置Swap大小为物理内存的25% - 50%但绝对大小建议在2GB - 8GB之间。例如4GB内存服务器Swap 2GB。16GB内存服务器Swap 4GB。64GB内存服务器Swap 8GB因为如此大的内存如果被用满Swap再大也于事无补反而可能因频繁交换导致整个系统不可用。关键点对于使用SSD的服务器频繁交换会损耗SSD寿命并影响性能。因此服务器优化的首要目标是监控内存使用通过优化应用、增加物理内存来避免触及Swap而不是依赖一个大Swap。2.3 安装过程中的分区实操以Ubuntu 22.04 LTS为例假设我们在一台16GB内存、512GB NVMe SSD的笔记本上安装Ubuntu并且需要休眠功能。启动安装程序到“安装类型”步骤时选择“其他选项”来手动分区。找到你的SSD通常是/dev/nvme0n1点击“新建分区表”这会清空所有数据请提前备份。创建分区EFI系统分区如果使用UEFI启动大小512MB - 1GB。类型EFI System Partition。挂载点/boot/efi。Swap分区大小16384 MB16GB等于物理内存。类型swap area。挂载点无需设置。根分区/大小剩余所有空间例如约 480GB。类型Ext4推荐或XFS。挂载点/。确认分区方案继续安装。注意对于不需要休眠的桌面用户或服务器在上述步骤中可以将Swap分区设置为4GB4096 MB并将剩余空间全部分给根分区。3. 系统安装后的内存调优让每一分内存都物尽其用系统装好了这只是开始。Linux提供了丰富的内核参数和工具来调整内存和交换空间的行为。很多时候我们感觉“内存不够用”未必是真不够可能是内核过于积极地将数据换出到Swap或者缓存策略不够高效。3.1 关键内核参数vm.swappiness 的深入解读与调整swappiness是一个从0到100的值它控制系统有多倾向于使用交换空间。值越高如60内核越积极地使用Swap即使物理内存还有不少空闲。值越低如10内核越不愿意使用Swap会尽量将数据保留在物理内存中。Ubuntu桌面版的默认值通常是60。这个默认值对于现代多内存的机器来说可能过于激进了。它会导致系统在物理内存压力并不大时就开始交换一些后台进程的内存当你切换回这些进程时就会感到卡顿。如何查看和调整# 查看当前 swappiness 值 cat /proc/sys/vm/swappiness # 临时修改重启后失效 sudo sysctl vm.swappiness10 # 永久修改 echo vm.swappiness10 | sudo tee -a /etc/sysctl.conf sudo sysctl -p # 重新加载配置调整建议桌面/开发机内存≥8GB使用SSD建议设置为10-30。我个人在16GB内存的机器上设为10这能确保在我进行编译、开大量浏览器标签页时系统优先使用物理内存保持流畅。只有当内存真的非常紧张时才会动用Swap。服务器需要更谨慎。如果服务器主要运行数据库如MySQL, PostgreSQL或内存缓存如Redis这些应用对内存访问延迟极度敏感可以设为1甚至0但0在某些极端情况下可能导致OOM Killer更早触发。对于通用Web服务器10-30也是一个合理的范围。使用HDD作为系统盘由于HDD交换性能极差更应该降低swappiness如10尽量避免交换或者强烈建议升级到SSD。3.2 另一个隐藏参数vm.vfs_cache_pressure这个参数控制内核回收用于目录和inode对象缓存的内存倾向。默认值通常是100。值越高100内核越倾向于回收这些缓存。值越低100内核越倾向于保留这些缓存。这些缓存dentries和inodes能极大加速文件系统的查找操作。对于文件操作频繁的场景如开发环境、Web服务器适当降低这个值可以提升性能。# 查看当前值 cat /proc/sys/vm/vfs_cache_pressure # 临时设置为50更倾向于保留缓存 sudo sysctl vm.vfs_cache_pressure50 # 永久设置 echo vm.vfs_cache_pressure50 | sudo tee -a /etc/sysctl.conf sudo sysctl -p对于大多数桌面和开发环境将其设为50是一个安全的优化。3.3 监控工具知己知彼百战不殆优化前、优化后都需要数据来说话。除了常用的free -h和htop这里介绍几个更专业的工具vmstat查看虚拟内存统计的利器。vmstat 1 5 # 每秒刷新一次共输出5次重点关注siswap in从Swap读入内存的数据量KB/s和soswap out从内存写出到Swap的数据量KB/s。如果它们持续大于0说明正在发生交换系统可能已经感到内存压力。smem以更直观的方式报告内存使用情况特别是能显示“比例集大小”PSS这对于评估进程实际占用的物理内存更有参考价值。sudo apt install smem smem -t -p # 以百分比形式显示/proc/meminfo这是所有内存信息的总源头。free和htop等工具的数据都来源于此。直接查看它可以获得最详细的信息。cat /proc/meminfo | grep -E “(Swap|Mem)” # 查看关键信息关注SwapCached它表示曾被换出、但又被换入且仍未修改的数据。这些数据仍然留在Swap中但如果有需要可以快速丢弃因为它们在内核中有副本。一个较大的SwapCached值通常意味着系统经历过内存压力。4. 动态管理Swap从Swap分区到Swap文件的灵活切换也许安装时你只分配了4GB Swap但现在一个大型数据集处理任务让你需要更多Swap缓冲。或者你最初没设Swap现在想加上。重装系统太麻烦了。Linux支持Swap文件它可以像Swap分区一样工作但创建和调整大小要灵活得多。4.1 创建Swap文件为现有系统添加Swap缓冲假设我们想在根目录下创建一个4GB的Swap文件。创建空文件使用dd命令创建一个充满零的文件。bs1M表示块大小为1MBcount4096表示块数总共4GB。sudo dd if/dev/zero of/swapfile bs1M count4096 statusprogress注意/swapfile是路径和文件名你可以放在其他有足够空间的分区但通常放在根目录下最简单。确保目标位置有足够空间用df -h查看。设置正确的权限Swap文件必须只有root可读可写否则有安全风险。sudo chmod 600 /swapfile格式化为Swap空间这个命令会向文件写入一个特殊的签名。sudo mkswap /swapfile启用Swap文件sudo swapon /swapfile现在用free -h或swapon --show命令你应该能看到新的Swap空间。永久生效编辑/etc/fstab文件在末尾添加一行让系统开机自动挂载这个Swap文件。echo /swapfile none swap sw 0 0 | sudo tee -a /etc/fstab4.2 调整Swap文件大小无需重装的扩容与缩容情况一增加Swap文件大小例如从4GB增加到8GB首先关闭当前的Swap文件sudo swapoff /swapfile删除旧文件创建新的大小的文件sudo rm /swapfile sudo dd if/dev/zero of/swapfile bs1M count8192 statusprogress # 创建8GB文件 sudo chmod 600 /swapfile sudo mkswap /swapfile重新启用并验证sudo swapon /swapfile free -h情况二减小Swap文件大小不常用更复杂减小尺寸不能直接操作因为dd创建的文件是稀疏还是紧凑会影响步骤。最安全的方法是sudo swapoff /swapfilesudo rm /swapfile按照“创建Swap文件”的步骤重新创建一个小尺寸的文件。4.3 Swap文件 vs Swap分区如何选择Swap分区优点传统方式性能可能在极细微层面略好因为是一个连续的磁盘区域。对于休眠支持某些引导加载器如旧的GRUB可能对Swap分区的识别更稳定。缺点调整大小极其困难通常需要借助GParted等工具调整分区表风险高。Swap文件优点极度灵活。创建、删除、调整大小都非常方便无需触动分区表。现代内核4.0和SSD上其性能与Swap分区几乎没有可感知的差异。是当前更推荐的方式尤其是对于UEFI系统和新手。缺点在极端古老的系统或某些特定的文件系统如Btrfs上可能需要额外配置。对于休眠需要确保引导加载器支持从Swap文件恢复现代Ubuntu的GRUB通常支持。结论对于绝大多数用户优先使用Swap文件。除非你有非常特殊的兼容性要求或者正在管理一个沿用旧规范的生产服务器。5. 高级场景与故障排查当内存问题真的来临时即使做好了规划与调优在长期运行后仍可能遇到棘手的内存问题。以下是两个常见高级场景的应对策略。5.1 诊断内存泄漏与“隐形”占用有时候free -h显示内存快用完了但htop里把所有进程的内存加起来却差很多。这部分“消失”的内存去哪了主要是内核缓存。Linux内核会利用空闲内存来缓存磁盘数据Buffers和Cached。这是为了提升性能当应用程序需要内存时内核会自动释放这部分缓存。所以在free命令的输出里看available这一列比看free列更有意义它代表了真正可被应用程序使用的内存。如果available内存确实很少但你又找不到明显的“元凶”进程可能是内核模块或驱动程序发生了内存泄漏。可以使用slabtop命令来查看内核对象缓存Slab的使用情况按占用排序sudo slabtop -o观察是否有某个缓存如dentry,inode_cache, 或某个驱动相关的对象异常增长且不释放。5.2 处理OOM Killer与优化应用内存使用当所有内存包括Swap都用尽时OOM Killer会被触发。它会根据一个复杂的算法oom_score选择一个“最佳”进程杀死。我们可以通过一些手段影响这个选择并优化应用。调整进程的OOM分数你可以手动降低重要进程如数据库、关键服务的oom_score使其在OOM时更不容易被杀死。# 查看进程的当前oom_score cat /proc/PID/oom_score # 通过oom_score_adj来调整范围是 -1000 到 1000。 # 值越低越不容易被杀死。将PID为1234的进程的adj设为-500 echo -500 | sudo tee /proc/1234/oom_score_adj要永久设置通常需要在服务的systemd unit文件如mysqld.service中添加OOMScoreAdjust-500。优化应用程序本身这是根本解决之道。对于Java应用合理设置JVM堆参数-Xmx,-Xms避免堆设置过大挤占系统内存或过小导致频繁GC。使用jstat,jmap等工具监控堆使用情况。对于Python应用注意循环引用可能导致垃圾回收无法释放内存。对于处理大数据的场景考虑使用迭代器generator而非一次性加载所有数据到列表。使用tracemalloc模块来追踪内存分配。对于C/C应用使用Valgrind的memcheck工具来检测内存泄漏。通用策略对于长时间运行的服务实现内存使用上限、定期重启通过systemd timer或容器编排工具是生产环境中常见的稳健策略。6. 针对特定工作负载的定制化内存方案不同的使用场景对内存的需求和优化侧重点完全不同。6.1 软件开发与编译环境特点需要频繁进行I/O操作读源码、写编译中间文件编译大型项目时内存消耗巨大且集中。Swap配置物理内存16GB以下建议4-8GB Swap文件。16GB以上2-4GB作为缓冲即可。将swappiness设为10避免编译中间期不必要的交换。内核参数vfs_cache_pressure可以设为50甚至更低如30因为文件查找操作非常频繁保留目录缓存能显著提升git status、文件搜索等操作的速度。实用技巧使用ccache来缓存C/C编译结果能极大减少重复编译的开销包括CPU和内存。对于Docker用户注意限制容器的内存使用-m参数防止单个容器耗尽主机内存。6.2 家庭服务器与媒体中心如Plex, Jellyfin特点长期运行服务多样文件共享、媒体转码、下载、家庭自动化内存占用相对平稳但存在峰值如视频转码。Swap配置物理内存的25%-50%但不超过8GB。例如8GB内存给2-4GB Swap。转码非常吃内存和CPU如果经常进行4K转码优先考虑升级物理内存。监控告警设置监控如Prometheus Grafana或简单的cron脚本当可用内存低于某个阈值如1GB或Swap使用率持续高于20%时发送告警邮件、Telegram等让你能及时介入。服务隔离如果使用Docker或LXC为每个容器或虚拟机分配明确的内存限制防止某个服务如崩溃的下载器拖垮整个系统。6.3 数据库服务器MySQL, PostgreSQL特点对内存延迟极度敏感大量使用内存作为缓存如InnoDB Buffer Pool, PostgreSQL的shared_buffers来加速查询。Swap策略物理内存必须充足。Swap仅作为紧急安全网大小设为2-4GB即可但要将swappiness设置为一个极低的值如1。目的是在物理内存真正耗尽时有一线生机让你登录系统进行维护而不是直接OOM导致数据库崩溃可能损坏数据。核心优化数据库的配置是关键。例如MySQL的innodb_buffer_pool_size通常设置为物理内存的50%-70%。绝对不要让这个值加上其他应用内存超过物理内存总量否则必然导致交换和性能骤降。文件系统缓存数据库自己管理缓存因此可以适当降低vfs_cache_pressure如50但效果不如在开发机上明显。重点还是给数据库分配足够且专属的内存。经过这一系列从安装规划到后期调优、从原理理解到实战操作的梳理你应该对Ubuntu下的内存管理有了一个立体而深入的认识。内存优化不是一劳永逸的它是一个结合硬件资源、软件负载和监控反馈的持续过程。我最深的一点体会是不要惧怕Swap但要理解并掌控它。把它看作一个“减压阀”或“安全气囊”而不是性能的延伸。在SSD时代一个大小适中、配置合理的Swap文件配合降低的swappiness能在不牺牲日常流畅度的前提下为你的系统提供宝贵的稳定性保障。下次当编译进程再被“Killed”时你就能从容地打开监控工具分析是真内存不足还是配置有待优化从而精准地解决问题了。