API로 받아온 10만 건 이상의 사용자 로그 데이터를 특정 키 기준으로 그룹핑하여 분석하려 합니다.
코드:
const data = Array.from({ length: 100000 }, (_, i) => ({
userId: `user_${i % 1000}`,
value: Math.random()
}));
const result = data.reduce((acc, cur) => {
if (!acc[cur.userId]) {
acc[cur.userId] = [];
}
acc[cur.userId].push(cur.value);
return acc;
}, {});
console.log(Object.keys(result).length);
오류: 데이터 양이 늘어날수록 처리 시간이 기하급수적으로 증가하며, 특정 시점에서 `FATAL ERROR: Ineffective mark-compacts near heap limit Allocation failed - JavaScript heap out of memory` 발생.
시도: `Map` 객체 사용 및 `forEach` 루프로 변경해봤으나 결과 동일함.
질문: JS 환경에서 이 정도 규모의 데이터 그룹핑 시 메모리 효율을 높일 수 있는 최적의 방법이 무엇입니까?
댓글9
-
행복한하루
2026.10.30 10:46
-
빗방울
2026.10.30 13:01
맞네요. 그냥 쌩으로 다 push해서 들고 있으려니까 터지는 듯ㄷㄷ
집계 데이터만 남기는 식으로 가거나 스트림 쓰는 게 답인 것 같네요.
-
빗방울
2026.10.30 16:31
맞네요ㅋㅋ 결국은 데이터 구조의 문제인 듯.
그냥 DB에서 GROUP BY 쳐서 가져오는 게
정신건강에 제일 이롭긴 하겠네요ㄷㄷ
-
빗방울
2026.10.30 11:48
혹시 TypedArray 같은 거 써보셨나요.
데이터 타입 고정해서 쓰면 메모리 훨씬 덜 먹을 것 같긴 한데.
일단 힙 메모리 설정부터 좀 늘려보시는 건 어떠세요ㅋㅋ
-
빗방울
2026.10.30 16:28
힙 늘리는 건 임시방편이라 결국 또 터질 것 같긴 하네요ㅋㅋ
TypedArray 쓰면 확실히 메모리는 덜 먹겠지만 구현하기 빡셀 듯ㄷㄷ
-
빗방울
2026.10.30 11:55
데이터 정렬부터 해놓고 처리하면 좀 나을지도 모르겠네요.
루프 돌 때 가비지 컬렉터가 일할 틈을 안 줘서 터지는 거 같음.
중간에 아주 짧게라도 비동기 처리 넣어서 런타임 숨통 좀 틔워보세요.
-
빗방울
2026.10.30 12:19
혹시 데이터 구조를 바꿔서 처리해보셨나요.
키-값 쌍으로 안 만들고 평탄화된 배열 상태에서 인덱스로만 관리하면 메모리 덜 먹을 것 같긴 함.
아니면 그냥 라이브러리 써서 처리하는 게 정신건강에 이로울 듯요ㅋㅋ
-
빗방울
2026.10.30 12:59
이거 혹시 데이터 가져올 때 한 번에 다 받는 건가요?
페이지네이션이나 커서 기반으로 끊어서 처리 안 하면
아무리 최적화해도 메모리 터지는 건 시간문제인 듯ㅋㅋ
-
빗방울
2026.10.30 15:56
이거 혹시 웹 워커(Web Worker) 써보셨나요?
메인 스레드에서 돌리면 UI까지 같이 멈춰서 더 끔찍할 텐데, 따로 빼서 처리하면 그나마 좀 낫지 않을까 싶네요ㅋㅋ
모든 이야기1454
가벼운 안부부터 깊은 생각까지, 함께 나눠요.
10만 건 정도의 데이터에서 힙 메모리 부족이 발생한다면, 데이터 자체의 크기보다는 객체 생성 및 관리 비용이 누적되어 가비지 컬렉션(GC) 부하가 커진 상황으로 보입니다. 특히
reduce내부에서 매번 새로운 객체나 배열을 참조하고 확장하는 과정에서 메모리 파편화가 발생할 수 있습니다.우선
Map을 사용하셨다고 했는데,Map은 일반 객체보다 빈번한 추가/삭제 작업에 최적화되어 있어 성능상 유리합니다. 다만, 결과값이 여전히 거대한 객체 형태라면 메모리 점유율은 비슷할 수밖에 없습니다. 만약 분석 목적이 단순히 합계나 평균 같은 집계라면, 배열에 모든 값을push하지 말고 즉시 계산하여 단일 숫자 값만 저장하는 방식으로 메모리 사용량을 획기적으로 줄여보시기 바랍니다.더불어, 데이터 규모가 계속 커질 예정이라면 클라이언트 사이드에서 처리하기보다 DB 쿼리(GROUP BY) 단계에서 처리하거나, Node.js 환경이라면
StreamAPI를 사용하여 데이터를 청크 단위로 읽어 처리하는 방식을 권장드립니다. 전체 데이터를 한 번에 메모리에 올리는 방식은 물리적인 힙 메모리 제한을 넘어서는 순간 반드시 런타임 에러를 유발하게 됩니다.