Skip to content
欢迎扫码关注公众号

Hexo 博客构建失败问题调查

刚刚配置到云效的流水线的时候是可以正常构建的,后来把大量的博客迁过来之后,构建报了 JavaScript heap out of memory 的错误:

log
<--- 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 插件:

bash
npm i cross-env -D

然后修改 package.jsonbuild 命令:

json
{
  "scripts": {
    "build": "cross-env NODE_OPTIONS='--max_old_space_size=3072' hexo generate",
  },
}

但是最近几天偶尔还是会构建失败,但是没有任何报错。

云效流水线的日志如下:

log
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 的健康诊断发现了一些端倪:

log
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 命令来查看内存的使用情况:

bash
free -h

但是因为刚刚重启了服务器,导致没看到出错时的 Swap 使用情况:

log
              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 文件的位置:

bash
swapon --show
log
NAME      TYPE SIZE   USED PRIO
/www/swap file   1G      0   -2

停用已有 Swap 文件:

bash
sudo swapoff -a

调整文件大小:

bash
sudo fallocate -l 4G /swapfile

将文件权限设置为仅 root 用户可读写:

bash
sudo chmod 600 /swapfile

格式化为 Swap 格式:

bash
sudo mkswap /swapfile

启用 Swap 文件:

bash
sudo swapon /swapfile

使用 free -hswapon --show 命令验证 Swap 文件是否已启用并显示为 4GB。

修改后暂时还没有再出现构建失败的情况。