-
Notifications
You must be signed in to change notification settings - Fork 0
Description
📝 프론트엔드 next.js 환경에서 메모리를 최적화 하기 위한 방법
📚 주제:
node 환경의 메모리 최적화를 위한 방법을 탐구한다.
📚 탐구 내용:
현재 메모리 사용량을 확인하기 위해서는 server를 커스텀 하여 확인할 수 있다.
메모리 사용량을 알아내는 방법은 GPT의 도움을 받아 process.memoryUsage()를 통해 알 수 있다는 것을 확인했다.
1. process.memoryUsage의 중요 요소


Node.js(Next.js) 애플리케이션 모니터링을 위한 메모리 인사이트 / if(kakaoAI)2024
해당 컨퍼런스 내용이 내가 고민하고 있는 개념적인 부분을 다뤄주고 있다.
1-1. 코드 적용
// server.js
const { createServer } = require('http');
const { parse } = require('url');
const next = require('next');
const dev = process.env.NODE_ENV !== 'production';
const app = next({ dev });
const handle = app.getRequestHandler();
app.prepare().then(() => {
const server = createServer((req, res) => {
const parsedUrl = parse(req.url, true);
handle(req, res, parsedUrl);
});
// 메모리 로깅
function logMemoryUsage() {
const memoryUsage = process.memoryUsage();
console.log(`RSS: ${memoryUsage.rss / 1024 / 1024} MB`);
console.log(`Heap Total: ${memoryUsage.heapTotal / 1024 / 1024} MB`);
console.log(`Heap Used: ${memoryUsage.heapUsed / 1024 / 1024} MB`);
console.log(`External: ${memoryUsage.external / 1024 / 1024} MB`);
}
setInterval(logMemoryUsage, 5000);
});커스텀한 server를 통해 서버를 시작하기 위해서는 package.json의 script를 node를 통해 실행시켜야 한다.
{
"scripts": {
"start": "node server.js",
},2. heap 메모리 제한
package.json의 script실행 시 다음과 같이 heap 메모리를 제한하여 관리할 수 있다.
{
"scripts": {
"start": "node --max-old-space-size=4096 server.js"
}
}해당 명령어로 서버 start시 server.js에서 작성한 console.log를 통해 다음과 같은 로그가 찍히는 것을 확인할 수 있었다.
RSS: 6878.95703125 MB
Heap Total: 3646.2421875 MB
Heap Used: 3577.541633605957 MB
External: 2535.8189821243286 MB
RSS: 6878.97265625 MB
Heap Total: 3646.2421875 MB
Heap Used: 3577.559700012207 MB
External: 2535.819083213806 MB
RSS: 7877.37109375 MB
Heap Total: 3597.78515625 MB
Heap Used: 3515.6298904418945 MB
External: 3877.6123657226562 MB그러나 --max-old-space-size 는 힙 메모리 에 대한 최대 크기를 설정할 뿐, 전체 메모리 사용량에는 영향을 주지 않는다고 한다.
해당 로그에서 RSS 는 Resident Set Size 약자로 프로세스가 실제로 사용하는 전체 메모리이다. 여기에는 힙 메모리 외에도 다음과 같은 메모리들이 포함된다.
- External Memory: V8 엔진 외부에서 사용하는 메모리 (e.g., 버퍼, C++ 확장 등)
- Code Segment: 코드 실행을 위한 메모리
- Stack Memory: 함수 호출 스택 메모리
따라서, --max-old-space-size로 제한된 것은 힙 메모리만이므로, 힙 외부 메모리(External, Code, Stack)는 제한되지 않는다.
전체 메모리를 제한하기 위해서는 Node.js 자체가 아닌, 실행 환경이나 운영 체제에서 메모리 제한을 설정 해야 한다.
3. node server 환경 설정
🔥 Trouble Shooting
또한, 위의 script를 사용하게 되면 build 후 start 실행 시 dev모드로 서버가 켜지는 것을 확인했다. (위에서 언급한 로그들도 dev모드의 로그임을 알게 되었다.)
이전에 start 스크립트 실행 시 node server.js를 통해 서버를 켜도록 설정 후 인프라 환경에 셋팅했을 때 OOM이 난 이유는 기본 heap 크기 설정이 2GB여서 였다. dev 모드로 서버가 켜지게 되면 최적화가 되지 않은 상태라 힙 메모리 사용량이 그 이상을 사용하고 있어 발생한 문제로 보인다.
🧑🚒 Problem Solving
우리는 build 후 production 환경으로 커스텀 한 서버 실행해야 한다.
따라서, script에서 production 모드로 서버가 켜질 수 있게 설정해 주어야 한다.
production 모드로 실행시키고자 한다면 script에서 NODE_ENV를 명시해줘야 한다.
// package.json
"scripts": {
"build": "yarn next build",
"start": "NODE_ENV=production node --max-old-space-size=3072 --max-semi-space-size=64 --optimize-for-size --trace-gc server.js"
}## ERROR LOG
$ yarn run start
yarn run v1.22.19
$ NODE_ENV=production node --max-old-space-size=3072 --max-semi-space-size=64 --optimize-for-size --trace-gc server.js
'NODE_ENV' is not recognized as an internal or external command,
operable program or batch file.NODE_ENV를 인식할 수 없음을 나타내는 로그가 나왔다.
🔥 Trouble Shooting
그러나 해당 script로 실행 시 Windows 환경에서는 NODE_ENV를 인식할 수 없었다.
🧑🚒 Problem Solving
따라서 우리는 Windows와 Linux 환경에 대한 Cross-env 설정이 필요하다.
## cross-env 의존성 추가
yarn add cross-env## cross-env를 통한 node 환경 설정
"scripts": {
"build": "yarn next build",
"start": "cross-env NODE_ENV=production node --optimize-for-size --trace-gc server.js"
}4. production모드로 실행 시 heap 메모리 로그

이전에 dev모드로 서버 start할 때와 다르게 heap 메모리 사용량이 1/15 이상 감소한 것도 확인할 수 있었다.
5. --optimize-for-size 설정 차이
설정전
설정후
--optimize-for-size 설정을 추가하게 되면 설정 전보다 heap 메모리 사용량이 감소하는 것을 확인 가능.
❓ 궁금해서 더 찾아본 것
기존 “next start”와 해당 스크립트는 어떤 차이가 있을까?
- next start vs node server.js 차이점
| 특징 | next start | node server.js (커스텀 서버) |
|---|---|---|
| 설정 간소화 | Next.js 기본 제공 기능으로 간단히 실행 가능 | 서버 로직 추가로 설정 복잡도 증가 |
| 유연성 | 기본 서버만 사용 가능 | HTTP 요청 처리, API 프록시 등 유연 |
| 성능 최적화 | 기본 설정으로 최적화 | 직접 최적화 가능 (e.g., 캐싱 로직) |
| 메모리 설정 제어 | NODE_OPTIONS로 간접 설정 | node 플래그로 직접 설정 가능 |
| -- |
next start
-
내장된 Next.js 서버 사용:
- Next.js가 기본 제공하는 서버를 실행합니다.
- 커스텀 로직을 추가하거나 직접 서버를 제어할 수는 없습니다.
-
간단한 배포:
- Next.js로 생성된 애플리케이션을 실행하는 가장 표준적인 방법입니다.
-
메모리 설정:
next start자체로는 Node.js 실행 환경을 직접 설정할 수 없기 때문에, 메모리 제한 등 Node.js 옵션을 제어하려면 다음과 같은 명령어로 실행해야 합니다.
NODE_OPTIONS="--max-old-space-size=4096" next start
node server.js
-
커스텀 서버:
- Next.js의
next()인스턴스를 활용해 HTTP 서버를 직접 생성하고, 추가 로직을 정의할 수 있습니다. - 예를 들어, 특정 API 프록시 처리, 커스텀 헤더 설정 등 Next.js 기본 서버에서 지원하지 않는 기능을 구현할 수 있습니다.
- Next.js의
-
유연성:
- HTTP 요청을 직접 제어하거나 다양한 미들웨어를 추가할 수 있는 유연성을 제공합니다.
-
메모리 설정:
- 커스텀 서버는 Node.js 환경에서 실행되므로, 다음과 같은 방식으로 메모리 설정을 제어할 수 있습니다:
node --max-old-space-size=4096 server.js
💡 참고 자료:
- https://speakerdeck.com/deepu105/v8-memory-usage-stack-and-heap
- https://fe-developers.kakaoent.com/2022/220519-garbage-collection/
- https://velog.io/@seyoung8239/V8-%EC%97%94%EC%A7%84-%EB%82%B4%EB%B6%80%EC%9D%98-%EB%A9%94%EB%AA%A8%EB%A6%AC-%EA%B4%80%EB%A6%AC
- https://gobae.tistory.com/116#V-%EC%--%--%EC%--%-C%EC%-D%--%--%ED%-E%--%--%EB%A-%--%EB%AA%A-%EB%A-%AC
- https://gobae.tistory.com/101
- https://deepu.tech/memory-management-in-v8/
- https://gist.github.com/stormwild/4bd3c1ec50ed055a363012a403b16365
- https://snird.medium.com/do-not-use-node-js-optimization-flags-blindly-3cc8dfdf76fd
- https://blog.heroku.com/node-habits-2016#7-avoid-garbage
- [ttps://devlog.mi.igaw.io/Next.js%EC%97%90%EC%84%9C%20%EB%A9%94%EB%AA%A8%EB%A6%AC%20%EB%88%84%EC%88%98%20%ED%99%95%EC%9D%B8%20%EB%B0%8F%20%EC%88%98%EC%A0%95%ED%95%98%EA%B8%B0](https://devlog.mi.igaw.io/Next.js%EC%97%90%EC%84%9C%20%EB%A9%94%EB%AA%A8%EB%A6%AC%20%EB%88%84%EC%88%98%20%ED%99%95%EC%9D%B8%20%EB%B0%8F%20%EC%88%98%EC%A0%95%ED%95%98%EA%B8%B0)
- https://coffeeandcakeandnewjeong.tistory.com/6
- https://velog.io/@server30sopt/heap-out-of-memory-%EC%97%90%EB%9F%AC-%ED%95%B4%EA%B2%B0%EA%B3%BC-%EB%A9%94%EB%AA%A8%EB%A6%AC-%EB%88%84%EC%88%98-%EA%B2%80%EC%82%AC
- https://puterism.com/deploy-next-js-with-ec2/
- https://forums.docker.com/t/build-a-nextjs-project-is-too-heavy-and-some-doubts/138748
https://www.youtube.com/watch?v=p2YFSJaoWWU
https://blog.eunsukim.me/posts/debugging-javascript-memory-leak-with-chrome-devtools

