Hexo 博客构建失败问题调查
刚刚配置到云效的流水线的时候是可以正常构建的,后来把大量的博客迁过来之后,构建报了 JavaScript heap out of memory 的错误:
<--- Last few GCs --->
[4606:0x75981e0] 72441 ms: Scavenge 932.7 (955.6) -> 932.6 (956.6) MB, 4.63 / 0.00 ms (average mu = 0.182, current mu = 0.199) allocation failure;
<--- JS stacktrace --->
FATAL ERROR: Ineffective mark-compacts near heap limit Allocation failed - JavaScript heap out of memory
----- Native stack trace -----
1: 0xca5580 node::Abort() [hexo]
2: 0xb781f9 [hexo]
3: 0xeca4d0 v8::Utils::ReportOOMFailure(v8::internal::Isolate*, char const*, v8::OOMDetails const&) [hexo]
4: 0xeca7b7 v8::internal::V8::FatalProcessOutOfMemory(v8::internal::Isolate*, char const*, v8::OOMDetails const&) [hexo]
5: 0x10dc505 [hexo]
6: 0x10dca94 v8::internal::Heap::RecomputeLimits(v8::internal::GarbageCollector) [hexo]
7: 0x10f3984 v8::internal::Heap::PerformGarbageCollection(v8::internal::GarbageCollector, v8::internal::GarbageCollectionReason, char const*) [hexo]
8: 0x10f419c v8::internal::Heap::CollectGarbage(v8::internal::AllocationSpace, v8::internal::GarbageCollectionReason, v8::GCCallbackFlags) [hexo]
9: 0x10f62fa v8::internal::Heap::HandleGCRequest() [hexo]
10: 0x1061967 v8::internal::StackGuard::HandleInterrupts() [hexo]
11: 0x150301a v8::internal::Runtime_StackGuard(int, unsigned long*, v8::internal::Isolate*) [hexo]
12: 0x193cef6 [hexo]
Aborted (core dumped)
这个问题官方的 Troubleshooting 里也有记录,node 项目大了可能都会出现这个问题。
我这里是安装了 cross-env 插件:
npm i cross-env -D
然后修改 package.json 的 build
命令:
{
"scripts": {
"build": "cross-env NODE_OPTIONS='--max_old_space_size=3072' hexo generate",
},
}
但是最近几天偶尔还是会构建失败,但是没有任何报错。
云效流水线的日志如下:
2025-04-21 17:53:41 [INFO] INFO 8130 files generated in 1.45 min
2025-04-21 17:53:57 [ERROR] run user script failed, exit code: 1
可以看到所有的文件都已经全部生成结束了,但是 npm run build
这个步骤却失败了。
怀疑是 build 消耗的资源太多了,于是通过 hexo generate
的 -c
参数来指定平行创建文件的数量。
改小了之后正常了一段时间,但是很快就有出现了类似错误,而且更加频繁。
最后还是通过 ECS 的健康诊断发现了一些端倪:
Apr 21 16:57:29 iZuf6akusmk4pak0skd0m3Z kernel: hexo invoked oom-killer: gfp_mask=0x100dca(GFP_HIGHUSER_MOVABLE|__GFP_ZERO), order=0, oom_score_adj=0
Apr 21 16:57:29 iZuf6akusmk4pak0skd0m3Z kernel: Out of memory: Killed process 541566 (hexo) total-vm:13776176kB, anon-rss:1444148kB, file-rss:15668kB, shmem-rss:0kB, UID:0 pgtables:34100kB oom_score_adj:0
Apr 21 17:53:55 iZuf6akusmk4pak0skd0m3Z kernel: iou-wrk-542496 invoked oom-killer: gfp_mask=0x101cca(GFP_HIGHUSER_MOVABLE|__GFP_WRITE), order=0, oom_score_adj=0
可以看到发生了 OOM,然后进程被系统 kill 掉了。这里的 total-vm
有点奇怪,大约是 13G,但是不可能有这么多,不太理解。
可以通过 free -h
命令来查看内存的使用情况:
free -h
但是因为刚刚重启了服务器,导致没看到出错时的 Swap 使用情况:
total used free shared buff/cache available
Mem: 1.8Gi 397Mi 1.2Gi 1.0Mi 344Mi 1.4Gi
Swap: 1.0Gi 0 1.0Gi
Mem 的情况因为有监控,build 时最高大约消耗 1.3Gi 左右内存,这个应该不会导致 OOM,所以怀疑是 Swap 空间太小导致的。当时 1G 的 Swap 空间可能被别的进程占用了,导致 build 时内存消耗超过了 Swap 空间。
解决办法是修改 Swap 空间的大小。
修改 Swap 空间的大小
首先是查看现有 Swap 文件的位置:
swapon --show
NAME TYPE SIZE USED PRIO
/www/swap file 1G 0 -2
停用已有 Swap 文件:
sudo swapoff -a
调整文件大小:
sudo fallocate -l 4G /swapfile
将文件权限设置为仅 root 用户可读写:
sudo chmod 600 /swapfile
格式化为 Swap 格式:
sudo mkswap /swapfile
启用 Swap 文件:
sudo swapon /swapfile
使用 free -h
或 swapon --show
命令验证 Swap 文件是否已启用并显示为 4GB。
修改后暂时还没有再出现构建失败的情况。