メモリ使用量の最適化方法

アプリケーションが成長し、機能が豊富になるにつれて、ローカルでの開発や本番ビルドの作成時により多くのリソースを必要とする場合があります。

Next.jsにおけるメモリの最適化と一般的なメモリ問題に対処するための戦略とテクニックを探ってみましょう。

依存関係の数を減らす

大量の依存関係を持つアプリケーションは、より多くのメモリを使用します。

バンドルアナライザーを使用すると、パフォーマンスとメモリ使用量を改善するために削除可能な大きな依存関係を調査できます。

experimental.webpackMemoryOptimizations を試す

v15.0.0 から、next.config.js ファイルに experimental.webpackMemoryOptimizations: true を追加することで、Webpackの動作を変更し、最大メモリ使用量を削減できます(ただし、コンパイル時間がわずかに増加する可能性があります)。

知っておくと良い: この機能は現在実験的であり、より多くのプロジェクトでテストされていますが、リスクは低いと考えられています。

next build--experimental-debug-memory-usage で実行する

14.2.0 から、next build --experimental-debug-memory-usage を実行すると、ビルド中にメモリ使用量に関する情報(ヒープ使用量やガベージコレクションの統計など)が継続的に出力されます。また、メモリ使用量が設定された制限に近づくと、ヒープスナップショットが自動的に取得されます。

知っておくと良い: この機能は、カスタム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 build または next dev コマンドを実行する際に、コマンドの先頭に NODE_OPTIONS=--inspect を追加します。これにより、デフォルトポートでインスペクターエージェントが公開されます。 ユーザーコードが開始する前にブレークしたい場合は、代わりに --inspect-brk を渡します。プロセスが実行されている間、Chrome DevToolsなどのツールを使用してデバッグポートに接続し、ヒープのスナップショットを記録・分析して、どのメモリが保持されているかを確認できます。

14.2.0 から、next build--experimental-debug-memory-usage フラグ付きで実行すると、ヒープスナップショットの取得が容易になります。

このモードで実行中、任意の時点でプロセスに SIGUSR2 シグナルを送信すると、プロセスはヒープスナップショットを取得します。

ヒープスナップショットはNext.jsアプリケーションのプロジェクトルートに保存され、Chrome DevToolsなどのヒープアナライザーで読み込んで、保持されているメモリを確認できます。このモードはまだWebpackビルドワーカーと互換性がありません。

詳細については、ヒープスナップショットの記録と分析方法を参照してください。

Webpackビルドワーカー

Webpackビルドワーカーを使用すると、Webpackコンパイルを別のNode.jsワーカー内で実行できるため、ビルド中のアプリケーションのメモリ使用量が減少します。

このオプションは、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にデプロイする場合は、ステージングデプロイのガイドを参照して、カスタムタスクが成功した後に本番環境にビルドをプロモートする方法を学べます。

ソースマップを無効にする

ソースマップの生成は、ビルドプロセス中に追加のメモリを消費します。

productionBrowserSourceMaps: falseexperimental.serverSourceMaps: false をNext.js設定に追加することで、ソースマップの生成を無効にできます。

知っておくと良い: 一部のプラグインはソースマップを有効にすることがあり、無効にするにはカスタム設定が必要な場合があります。

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サーバーのメモリ使用量は最終的に同じになります。