如何优化内存使用

随着应用程序功能日益丰富,在本地开发或构建生产环境时可能会消耗更多资源。

下面我们将探讨优化内存和解决 Next.js 中常见内存问题的策略与技巧。

减少依赖项数量

依赖项较多的应用程序会占用更多内存。

使用打包分析器可以帮助检查应用程序中的大型依赖项,移除不必要的依赖可以提升性能和减少内存占用。

尝试 experimental.webpackMemoryOptimizations

v15.0.0 开始,您可以在 next.config.js 中添加 experimental.webpackMemoryOptimizations: true 来调整 Webpack 行为,这将降低最大内存使用量,但可能会轻微增加编译时间。

须知:该功能目前处于实验阶段,需要在更多项目中测试,但被认为风险较低。

使用 --experimental-debug-memory-usage 运行 next build

14.2.0 开始,您可以运行 next build --experimental-debug-memory-usage,在此模式下 Next.js 会在构建过程中持续输出内存使用信息,包括堆内存使用情况和垃圾回收统计。当内存使用接近配置限制时,还会自动生成堆快照。

须知:此功能与 Webpack 构建工作线程选项不兼容,除非您有自定义 webpack 配置,否则该选项会自动启用。

记录堆内存分析文件

为了排查内存问题,您可以记录 Node.js 的堆内存分析文件,并在 Chrome DevTools 中加载以识别潜在的内存泄漏源。

在终端中启动 Next.js 构建时,向 Node.js 传递 --heap-prof 标志:

node --heap-prof node_modules/next/dist/bin/next build

构建结束后,Node.js 会生成一个 .heapprofile 文件。

在 Chrome DevTools 的 Memory 标签页中,点击 "Load Profile" 按钮即可可视化分析该文件。

分析堆内存快照

您可以使用检查工具来分析应用程序的内存使用情况。

运行 next buildnext dev 命令时,在命令开头添加 NODE_OPTIONS=--inspect。这将在默认端口上暴露检查器代理。如果希望在用户代码执行前中断,可以改用 --inspect-brk。当进程运行时,您可以使用 Chrome DevTools 等工具连接到调试端口,记录并分析堆内存快照以查看内存占用情况。

14.2.0 开始,您还可以使用 --experimental-debug-memory-usage 标志运行 next build,这会使获取堆快照更加容易。

在此模式下运行时,您可以随时向进程发送 SIGUSR2 信号,进程将生成堆快照。

堆快照将保存在 Next.js 应用程序的项目根目录中,可以在任何堆分析器(如 Chrome DevTools)中加载以查看内存保留情况。此模式目前尚不兼容 Webpack 构建工作线程。

有关详细信息,请参阅如何记录和分析堆快照

Webpack 构建工作线程

Webpack 构建工作线程允许在单独的 Node.js 工作线程中运行 Webpack 编译,这将减少构建期间的应用程序内存占用。

v14.1.0 开始,如果应用程序没有自定义 Webpack 配置,此选项将默认启用。

如果您使用的是旧版 Next.js 或有自定义 Webpack 配置,可以通过在 next.config.js 中设置 experimental.webpackBuildWorker: true 来启用此选项。

须知:此功能可能与某些自定义 Webpack 插件不兼容。

禁用 Webpack 缓存

Webpack 缓存将生成的 Webpack 模块保存在内存和/或磁盘上以提高构建速度。这有助于提升性能,但也会增加应用程序的内存占用以存储缓存数据。

您可以通过为应用程序添加自定义 Webpack 配置来禁用此行为:

next.config.mjs
/** @type {import('next').NextConfig} */
const nextConfig = {
  webpack: (
    config,
    { buildId, dev, isServer, defaultLoaders, nextRuntime, webpack }
  ) => {
    if (config.cache && !dev) {
      config.cache = Object.freeze({
        type: 'memory',
      })
    }
    // 重要:返回修改后的配置
    return config
  },
}

export default nextConfig

禁用静态分析

类型检查和代码检查可能会消耗大量内存,特别是在大型项目中。 然而,大多数项目都有专门的 CI 运行器来处理这些任务。 当构建在 "Linting and checking validity of types" 步骤中出现内存不足问题时,您可以在构建期间禁用这些任务:

next.config.mjs
/** @type {import('next').NextConfig} */
const nextConfig = {
  eslint: {
    // 警告:即使项目存在 ESLint 错误,此设置也允许生产构建成功完成
    ignoreDuringBuilds: true,
  },
  typescript: {
    // !! 警告 !!
    // 即使项目存在类型错误,也允许生产构建成功完成
    // !! 警告 !!
    ignoreBuildErrors: true,
  },
}

export default nextConfig

请注意,这可能会因类型错误或代码检查问题导致部署失败。 我们强烈建议仅在静态分析完成后才将构建推送到生产环境。如果您部署到 Vercel,可以查看暂存部署指南了解如何在自定义任务成功后提升构建至生产环境。

禁用源映射

生成源映射会在构建过程中消耗额外内存。

您可以通过在 Next.js 配置中添加 productionBrowserSourceMaps: falseexperimental.serverSourceMaps: false 来禁用源映射生成。

须知:某些插件可能会启用源映射,可能需要自定义配置才能禁用。

Edge 运行时内存问题

Next.js v14.1.3 修复了使用 Edge 运行时的内存问题。请升级到此版本(或更高版本)以确认是否解决了您的问题。

预加载入口

当 Next.js 服务器启动时,它会将每个页面的 JavaScript 模块预加载到内存中,而不是在请求时加载。

这种优化以更大的初始内存占用为代价,换取更快的响应时间。

要禁用此优化,请将 experimental.preloadEntriesOnStart 标志设置为 false

import type { NextConfig } from 'next'

const config: NextConfig = {
  experimental: {
    preloadEntriesOnStart: false,
  },
}

export default config

Next.js 不会卸载这些 JavaScript 模块,这意味着即使禁用此优化,如果最终请求了所有页面,Next.js 服务器的内存占用最终也会相同。