如何優化記憶體使用

隨著應用程式功能日益豐富,在本地開發或建立生產版本時可能會需要更多資源。

讓我們探討一些優化記憶體的策略和技巧,並解決 Next.js 中常見的記憶體問題。

減少依賴項數量

擁有大量依賴項的應用程式會使用更多記憶體。

套件分析工具 (Bundle Analyzer) 可以幫助您檢查應用程式中可能移除的大型依賴項,以提升效能和記憶體使用效率。

嘗試 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 建置時傳遞 --heap-prof 標記給 Node.js:

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 伺服器的記憶體佔用最終也會相同。

On this page