← 返回首页

一条注释引发的血案:我的服务器为什么每次上传文件就卡死

服务器运维 亲身经历 公开
内容简要
服务器因 systemd 配置文件行尾注释导致内存限制失效,上传大文件时卡死。
坑点
systemd 配置文件不支持行尾注释,导致内存限制设置失效。
注意事项

1. 确保systemd配置文件中的内存限制设置正确,注释应单独一行。

  • 2. 为JVM设置堆上限,避免内存耗尽。
  • 3. 验证配置的实际数值,确保生效。
  • 4. 在小内存机器上运行多个服务时,注意内存分配和限制。

一条注释引发的血案:我的服务器为什么每次上传文件就卡死

一、案发现场

事情是这样的:我的腾讯云轻量服务器(2G 内存)有个毛病——每次上传、保存文件的时候,它就卡死。不是慢,是彻底僵住,SSH 都连不上,只能去控制台点重启。

重启完一切正常,用着用着,再上传个大文件,又死。如此循环,我一度以为这台机器中了邪。

二、第一反应:肯定是内存爆了

上传大文件卡死,第一直觉就是内存。于是登上去翻内核日志找 OOM 记录——

结果一条都没有。

这下有点懵。如果真是内存耗尽被 OOM Killer 杀进程,日志里一定会写 Out of memory: Killed process。可它干干净净,什么都没有。

后来才想明白:它不是被杀死的,是被活活憋死的。

三、转折点:一行被 systemd 嫌弃的注释

翻日志时,我注意到一条被我忽略很久的警告:

Invalid memory limit '512M   # 硬上限: 超过直接 OOM kill...', ignoring

看懂这行的时候,我整个人是裂开的。

我明明给两个 Java 服务都配了内存限制 512M,但 systemd 不支持行尾注释。它把 # 后面的中文说明当成了数值的一部分,512M # 硬上限... 当然不是合法数字,于是 systemd 一句 "ignoring",把我的限制直接扔了。

我以为是保险丝,其实那保险丝从装上去那天就没接过线。

验证了一下,果然:

MemoryMax=infinity    ← 本该是 512M

四、真凶:三个"大胃王"和一块快要撑爆的 swap

顺着查下去,画面就很清楚了:

pitlog.jar     692M   ████████████████
ydt-server     320M   ████████
mysqld         219M   █████
────────────────────────────────
总内存 1.9G,available 只剩 292M
Swap 1G,已经吃掉 582M

更要命的是 vmstat 的第一行:

si=112   so=585

si/so 非零,就是系统正在疯狂把内存往硬盘上倒腾(换页)。

完整的事故链条是这样的:

配置失效 → 两个 JVM 裸奔、没有堆上限 → 内存被吃光 → 上传时堆瞬间膨胀,缺口爆掉 → 系统拼命往 swap 换页 → swap 在磁盘上,IO 一堵整机就僵 → SSH 想登进来要新开进程,内存分配不到,直接登不上​ → 只能硬重启。

所以日志里没有 OOM 记录——它压根没走到"杀进程"那一步,是在换页的泥潭里活活卡死的。

五、修复:给两道门都上锁

改起来其实就三步:

第一步,把注释挪到单独一行(这个坑,我是真的一脚踩满):

[Service]
# 硬上限,留足系统缓冲
MemoryMax=700M
MemorySwapMax=1500M

第二步,给 JVM 也设死堆上限。systemd 限的是整个进程,JVM 堆不单独限,它会在上限里面顶到顶:

-Xms384m -Xmx650m -XX:MaxMetaspaceSize=160m -XX:+UseSerialGC

小内存机器上 UseSerialGC 是真香,G1 光自己就要吃掉上百兆。

第三步,重启验证:

MemoryMax=734003200    ← 700MiB,生效了
-Xmx650m               ← 堆也限住了

修完的对比:

修复前修复后
内存限制infinity700M / 900M ✅
JVM 堆没设-Xmx 已设 ✅
可用内存292M500M+ ✅
最坏情况整机宕机,硬重启​单进程被 kill,10 秒自动拉起

六、四句话总结这次学到的

  1. systemd 配置文件不支持行尾注释。​ 一行 #,能让你的内存限制静默失效、毫无提示地裸奔几个月。
  2. 没有 OOM 日志 ≠ 不是内存问题。​ 换页颠簸能把机器憋死在"杀进程"之前,日志里连尸体都找不到。
  3. "配了"不等于"生效了"。​ 验证一定要落到 systemctl show 的实际数值上,别信配置文件里写着什么。
  4. 2G 机器跑双 Spring Boot + MySQL + Docker,本来就是在走钢丝。​ 限制只是让摔下来不致命,真想睡安稳觉,还是得升到 4G。
排查顺序也可以记一下:dmesg 找 OOM 记录 → free 看 available → vmstat 看 si/so → ps 排序看谁在吃。四步走完,病因基本就藏在里面了。
本文内容仅代表作者个人观点、经历或转述,不代表任何官方立场,仅供参考,不构成任何专业建议。据此操作产生的风险由读者自行承担。
发布于 2026-11-10 14:30:31 ID: 83