一个非常奇怪的“JavaScript堆内存不足”问题

Nic*_*ull 5 node.js docker circleci yarnpkg

我正在尝试使用具有 32GB RAM 的基于 ARM 的计算机(特别是 )在 CircleCI 上构建 Next.js 项目arm.xlarge。然而,它似乎很快就退出并出现内存不足的错误。我尝试将节点进程的内存一直增加到机器的内存,但没有运气 - 我收到了相同的错误。

特别奇怪的是,GC 的内存利用率极低(3.5MB),并且它在亚秒级的时间内退出!

如果我将资源类型替换armx86_64资源类型,并为平台构建 Docker 映像,则此构建确实有效x86_64。显然这不能满足我的需求,但可以验证构建是否有效。

是什么可能导致这种非常奇怪的行为?我还能做什么来进一步调试这个问题?

我尝试过的

  • 更改 Node 版本,范围从 14 到 18.8.0
  • 更改机器资源大小
  • 更改 Docker 的选项,包括--memoryextra-build-args构建作业字段添加标志
  • 删除yarn.lock
  • 清除节点缓存
  • 删除node_modules文件夹

相关资源:

这是跟踪:

#16 [11/11] RUN NODE_OPTIONS="--max_old_space_size=8192" yarn build
#16 sha256:da0777711cb35943386ef4812f2df1ff4932fb5bee717be330a217104e5240c7
#16 0.178 
#16 0.178 <--- Last few GCs --->
#16 0.178 
#16 0.178 [1:0x570e320]      100 ms: Mark-sweep 1.2 (3.5) -> 1.2 (3.5) MB, 2.2 / 0.0 ms  (average mu = 0.818, current mu = 0.007) allocation failure scavenge might not succeed
#16 0.178 [1:0x570e320]      102 ms: Mark-sweep (reduce) 1.2 (3.5) -> 1.2 (3.5) MB, 2.3 / 0.0 ms  (average mu = 0.704, current mu = 0.006) last resort GC in old space requested
#16 0.178 [1:0x570e320]      104 ms: Mark-sweep (reduce) 1.2 (2.5) -> 1.1 (3.5) MB, 2.3 / 0.0 ms  (average mu = 0.549, current mu = 0.010) last resort GC in old space requested
#16 0.178 
#16 0.178 
#16 0.178 <--- JS stacktrace --->
#16 0.178 
#16 0.178 FATAL ERROR: CALL_AND_RETRY_LAST Allocation failed - JavaScript heap out of memory
#16 ERROR: process "/bin/sh -c NODE_OPTIONS=\"--max_old_space_size=8192\" yarn build" did not complete successfully: exit code: 132
------
 > [11/11] RUN NODE_OPTIONS="--max_old_space_size=8192" yarn build:
------
Dockerfile:32
--------------------
  31 |     
  32 | >>> RUN NODE_OPTIONS="--max_old_space_size=8192" yarn build
  34 |     
--------------------
error: failed to solve: rpc error: code = Unknown desc = process "/bin/sh -c NODE_OPTIONS=\"--max_old_space_size=8192\"   CI_BUILD=${CI_BUILD} DEPLOYMENT_VERSION=${DEPLOYMENT_VERSION} yarn build" did not complete successfully: exit code: 132
Run Code Online (Sandbox Code Playgroud)

以下是 Dockerfile 的相关部分:

FROM node:14.18.0-alpine
WORKDIR /app

RUN apk update
RUN apk add python3
RUN apk add git gnupg jq g++ make py3-pip

COPY package.json yarn.lock ./
RUN yarn
RUN yarn add pm2@5.2.0 --global

COPY . .

RUN NODE_OPTIONS="--max_old_space_size=8192" yarn build

EXPOSE 3001

CMD [ "npx", ... ]
Run Code Online (Sandbox Code Playgroud)

这是 CircleCI 的工作config.yml

  build_and_push_image:
    machine:
      image: ubuntu-2004:202101-01
    resource_class: arm.xlarge
    steps:
      - checkout
      - docker/pull:
          images: 'node:16.14.2'
      - aws-ecr/build-and-push-image:
          aws-access-key-id: AWS_ACCESS_KEY_ID
          aws-secret-access-key: AWS_SECRET_ACCESS_KEY
          aws-cli-version: latest
          create-repo: true
          skip-when-tags-exist: true  
          dockerfile: Dockerfile
          extra-build-args: >
            --build-arg GPG_ENCRYPT_PASSPHRASE
            --build-arg BUILD_STAGE
            --build-arg CI_BUILD=true
          platform: linux/arm64/v7
          push-image: true
          registry-id: AWS_ACCOUNT_ID
          region: $AWS_REGION
          repo: $PROJECT_NAME
          tag: $version_tag
Run Code Online (Sandbox Code Playgroud)

Nic*_*ull 1

经过几个小时的反复试验和调试,我修复了以下更改config.yml

\n
\n build_and_push_image:\n 机器:\n 图像: ubuntu-2004:202101-01\n 资源类:arm.xlarge\n 步骤:\n - 签出\n - docker/pull:\n 图像: \'node:16.14 .2\'\n - aws-ecr/build-and-push-image:\n aws-access-key-id: AWS_ACCESS_KEY_ID\n aws-secret-access-key: AWS_SECRET_ACCESS_KEY\n aws-cli-version: 最新\n create-repo: true\nskip-when-tags-exist: true \n dockerfile: Dockerfile\n extra-build-args: >\n --build-arg GPG_ENCRYPT_PASSPHRASE\n --build-arg BUILD_STAGE\n --build-arg CI_BUILD=true\n \n- 平台:linux/arm64/v7\n+ 平台:linux/arm64\n \n 推送映像:true\n 注册表 ID:AWS_ACCOUNT_ID\n 区域:$AWS_REGION\ n 存储库:$PROJECT_NAME\n 标签:$version_tag\n
\n

我不确定为什么这会起作用,但对于将来受此阻碍的其他人来说,这是我最好的想法:

\n\n
docker context create builder\n\n#\xc2\xa0This here is interesting - it is using qemu to emulate for builds \n#\xc2\xa0See https://github.com/tonistiigi/binfmt\n\ndocker run --privileged --rm tonistiigi/binfmt --install all\ndocker --context builder buildx create --use\ndocker --context builder buildx build \\\n  -f "${PARAM_PATH}"/"${PARAM_DOCKERFILE}" \\\n  ${docker_tag_args} \\\n  --platform "${PARAM_PLATFORM}" \\\n  --progress plain \\\n  "$@" \\\n  "${PARAM_PATH}"\n\n
Run Code Online (Sandbox Code Playgroud)\n\n