코딩일상
RangeError: Invalid string length 에러 해결 방법 본문
let result = connection.query('select * from table')
위와 같이 DB를 조회 하여 result에 값을 담는 과정에서 RangeError: Invalid string length 라는에러가 발생하였다.
처음 보는 에러 여서 ?? 이게 뭐지 하고 이 에러에 대해 알아보니 이런 뜻이었다.
"RangeError: Invalid string length" 오류는 JavaScript에서 허용되는 최대 길이를 초과하는 길이의 문자열을 만들려고 할 때 발생
길이가 2^53-1(JavaScript의 최대 안전 정수)보다 큰 문자열을 만들려고 할 때. 이것은 매우 큰 문자열을 연결하여 문자열을 만들거나 길이가 매우 큰 문자열을 만들려고 할 때 발생할 수 있다.
데이터가 너무 커서 문제가 없을까 생각은 해보았지만 이때까지 한번도 이러한 문제를 직면한적이 없었는데
드디어 이러한 경우를 접하게되었다.
어쩄든 에러를 맞이한만큼 기쁜 마음으로(?) 문제를 해결할 방법들에 알아보았다.
총 3가지 방법으로 이 문제를 해결 할수있을 거 같았다.
- stream을 이용하여 한번에 데이터를 받지 않고 결과를 chunk로 받아서 해결
- 한번에 받는 데이터를 제한하기
- 다른 데이터 구조로 결과값을 받기
1번의 경우는 솔직히 내가 제대로 이해하지 못하여 사용하기가 어려웠다.
그래서 2,3번 방식중 하나의 방식을 선택을 해야했다.
3번의 경우를 하기위해서는 어쨌든 데이터를 조회를 한것을 특정변수가 받아서 해결을 해야하는데
조회 자체가 너무 값을 가져오다 보니 데이터를 가져오는 과정자체에서 사용되는 메모리 문제또한 컸다.
이미 기존에 사용되어지고있는 기능들이 많아 메모리를 사용 할수 있는
범위를 줄여 놓는것이 안정성을 위해서 좋다고 생각을 했기 때문이다.
그렇다면 한번에 받는 데이터를 줄여 처리를 위한 필요한 메모리를 줄여야겠다 생각을 하였다.
그래서 아래와 같이 조회 쿼리를 LIMIT과 OFFSET을 사용하기로 하였다.
const query = `SELECT * FROM "${table}" limit ${limit} offset ${limit * index};`
여기서 또다른 문제에 직면하게되었는데 새로운 에러가 발생을 하였다.
heap over flow
?? 갑자기 왜 heap에서 overflow가 나지 했는데 limit값을 임의로 설정했는데
limit을 적용하여 받은 데이터 조차 양이 많아 heap over flow를 하게된것이었다.
JavaScript 동작원리를 보다 보면 항상 자주 보던 그림이다.
heap에 우리는 변수의 값들을 저장하고 사용이 끝나면 가비지 컬랙터가 자동으로 이를 지워준다.
하지만 지워지기 전에 저장될 값이 너무 많아 사용할수 있는 heap의 범위를 넘어 버린것이다.
(이것도 제대로 생각안하고 그냥 아무생각없이 대충 limit정해 버린 나의 잘못이었다.)
그렇다면 여기서 고민이 들었다.
여기서 그러면 heap의 총 크기는 얼마일까??
그리고 코드가 실행되면서 얼마만큼의 heap을 차지 하는 것일까???
이를 어떻게 확인 해보지??
의문을 가지고 구글에 검색을 해보니 역시 갓 구글 답이 나왔다.
//1번 사용양을 최대로 찍어보기
const array = [];
while (true) {
// This makes the array bigger on each iteration
array.push(new Array(10000000));
const memory = process.memoryUsage();
console.log((memory.heapUsed / 1024 / 1024 / 1024).toFixed(4), 'GB');
}
//2번 V8엔진에 heapSize 찍어보기
const v8 = require("v8");
let size = v8.getHeapStatistics().heap_size_limit;
console.log(size / 1024 / 1024 / 1024);
이것을 통해 최대 heap 사이즈 알수있었다.
최대 heap 사이즈는 node 버전 별로 다르니 참고 하면 좋다
(각자 한번 자기가 사용할수 있는 heap 최대 사이즈는 어떻게 되는지 알아보며 좋을듯하다)
만약 정해진 heap 사이즈보다 크게 하여 사용을 하고싶다면 아래의 명령어를 사용하면 된다.
(아래의 경우는 heap size를 2GB로 사용하겠다는 뜻, 여기서 old-space란 heap이 구성되어지는 부분중 하나이다.)
node --max-old-space-size=2048 yourScript.js
이렇게 하면 당장은 Node.js 애플리케이션의 성능이 향상될 수 있다.
그러나 힙 크기를 너무 높게 설정하면 성능 문제가 발생하거나 시스템에 할당된 힙을 수용할 만큼
사용 가능한 메모리가 충분하지 않은 경우 충돌이 발생할 수도 있다 그러니 잘 파악해서 사용하길!!
어쨌든 결국 이렇게 heap사이즈를 파악하는 방법을 알았으니 이를 적용하여
문제를 해결해보기로 하고 진행되는 코드 사이에 콘솔을 심어 실행을 해보았다.
엥?? 왜 heap 총 사이즈가 바뀌는 거지?? 라는 의문이 들었다.
정말 공부를 제대로 하지 않았다는게 깨닫는 순간이었다.
이 이유에 대해 좀더 찾아보니
V8 엔진은 힙을 여러 영역으로 나누는 세대별 가비지 수집기를 사용하여 메모리 사용량을 동적으로 조정한다.
추가)heap은 처음에 "new space" 영역과 "old space" 영역으로 나뉩니다.
new space(from,to)은 자주 생성 및 소멸되는 수명이 짧은 개체에 사용되는
반면, old space은 응용 프로그램 수명 동안 지속되는 수명이 긴 개체에 사용되어진다.
내가 이해한 바로는 가비지 컬랙터(GC)에서 살아남은 것들을 to-> from->old 순으로 메모리를 차지하는것들을 옮긴다
솔직히 아직도 이해가 완벽하게 되진 않았지만 아.. 이런식이 있구나를 알게된 순간이었다.
추후 공부를 좀더 하고 이해가되면 이부분에 대해서도 정리를 해보아야겠다.
일단은 이런이유때문에 Heap 사이즈는 필요한 만큼 유동적으로 변동이된다는 사실을 파악하고
최대 사이즈를 넘지 않도록 limit 범위를 설정하여 코드를 실행을 하게되니 모든것이 안정적으로 해결이 되었다.
RangeError: Invalid string length라는 하나의 에러 덕분에 JavaScript에 대해 좀더 제대로 파악할수있었고
다양한 방식들로 heap메모리 관리를 하는법을 알게되었던 계기가 되었다!!
'기록 > Troubleshooting' 카테고리의 다른 글
[caffeine 컴파일에러 ]class file has wrong version 55.0, should be 52.0 (0) | 2023.07.04 |
---|---|
Failed to determine a suitable driver class (0) | 2023.04.03 |
Console Ninja 설치 후 발생한 에러 (0) | 2023.02.17 |
[오류 해결] CastError: Cast to ObjectId failed for value "값" at path "_id" for model "모델명" (0) | 2022.08.02 |
PM2 stop/ kill 하는법 (0) | 2022.07.26 |