실수로 React가 서버에서 렌더링되면 Node_env! = 생산이있을 때 메모리 누출이 발생한다는 것을 발견했습니다. 구체적인 문제 : https://github.com/facebook/react/issues/7406. 노드와 반응 동형 및 기타 기술을 광범위하게 사용하면 노드 측 메모리 누출과 같은 문제가 우리의 관심을 끌 수 있습니다. 노드가 메모리 누출이 발생하기 쉬운 이유와 발생 후 문제 해결 방법은 무엇입니까? 다음은 간단한 소개와 예입니다.
우선, 노드는 V8 엔진을 기반으로하며 메모리 관리 방법은 V8과 일치합니다. 다음은 V8의 관련 메모리 효과에 대한 간단한 소개입니다.
V8 메모리 제한
노드는 V8에 구축되며 V8을 통해 JS 객체를 할당하고 관리 할 수 있습니다. V8은 메모리 사용에 한계가 있습니다 (구식 메모리 64 비트 시스템의 경우 약 1.4G, 32 비트 시스템의 경우 약 0.7G, 차세대 메모리 64 비트 시스템의 경우 약 32MB, 32 비트 시스템의 경우 약 16MB). 이러한 제한에 따라 큰 메모리 객체는 작동 할 수 없습니다. 이 경계가 실수로 터치하면 프로세스가 종료됩니다.
원인 : V8은 쓰레기 수집을 수행 할 때 JavaScript 응용 프로그램 논리를 차단 한 다음 쓰레기 수집이 끝날 때까지 JavaScript 응용 프로그램 논리를 다시 실행합니다. 이 동작을 "정지"라고합니다. V8의 힙 메모리가 1.5GB 인 경우 V8이 작은 쓰레기 수집을 수행하는 데 50ms 이상이 걸리며 비 분리 쓰레기 수집에 1 초 이상이 걸립니다.
Set the new generation memory and the old generation memory to crack the default memory limit by setting node --max-old-space-size=xxx (unit MB) and node --max-new-space-size=xxx (unit KB).
V8 힙 구성
V8 힙은 실제로 구식과 새로운 세대의 두 부분으로 구성되어 있지 않습니다. 힙은 여러 다른 영역으로 나눌 수 있습니다.
GC 재활용 유형
증분 GC
메모리 공간을 스캔 할 때 쓰레기 수집기가 쓰레기를 수집하고 (추가) 스캔 사이클의 끝에서 쓰레기를 지우는지 여부를 나타냅니다.
비 분개 GC
비 분쇄 쓰레기 수집기를 사용할 때는 쓰레기가 수집하자마자 비어 있습니다.
쓰레기 수집기는 새로운 세대 메모리 지역, 구식 포인터 지역 및 구식 데이터 영역에 대한 쓰레기 수집 만 수행 할 것입니다. 객체는 먼저 공간을 덜 차지하는 새로운 세대 메모리에 들어갑니다. 대부분의 객체는 빠르게 실패하며 비 분개 GC는 이러한 소량의 메모리를 직접 재활용합니다. 일부 객체를 일정 기간 동안 재활용 할 수없는 경우 구식 메모리 영역에 입력됩니다. 이 영역은 드물게 증분 GC를 실행하고 오랜 시간이 걸립니다.
그렇다면 메모리 누출은 언제 발생합니까?
메모리 누출 경로
노드의 메모리 구성은 주로 V8을 통해 할당 된 부분과 노드 자체에 의해 할당 된 부분입니다. V8의 쓰레기 수집의 주요 제한은 V8의 힙 메모리입니다. 메모리 누출의 주된 이유 : 1. 캐시; 2. 대기열 소비는시의 적절하지 않다. 3. 스코프가 릴리스되지 않았습니다
메모리 누출 분석
V8 메모리 사용량 확인 (단위 바이트)
process.memoryUsage (); {Ress : 47038464, Heaptotal : 34264656, Heapuss : 2052866}Ress : 과정의 상주 메모리 부분
힙합, 인용 : V8 힙 메모리 정보
시스템 메모리 사용 확인 (단위 바이트)
os.totalmem()
os.freemem ()
총 시스템 메모리와 유휴 메모리를 반환합니다
쓰레기 수거 로그를 봅니다
노드 --trace_gc -e "var a = []; for (var i = 0; i <10000000; i ++) {a.push (new Array (100));}">> gc.log // 출력 쓰레기 수집 로그
노드 --prof // 출력 노드 실행 성능 로그. Windows-Tick.processor를 사용하여 볼 수 있습니다.
분석 모니터링 도구
V8-Profiler는 V8 힙 메모리의 스냅 샷을 캡처하고 CPU를 분석합니다.
Node-HeapDump는 V8 힙 메모리의 스냅 샷을 잡습니다
노드 마운트 분석 스택 사용
Node-Memwatch는 쓰레기 수거 상황에 대해 듣습니다
노드-마워치
memwatch.on ( 'stats', function (informs) {console.log (info)}) memwatch.on ( 'Leak', function (info) {console.log (info)})통계 이벤트 : 전체 힙 쓰레기 수집이 수행 될 때마다 통계 이벤트가 트리거됩니다. 이 이벤트는 메모리 통계를 통과합니다.
{ "num_full_gc": 17, // 몇 개의 풀 스택 쓰레기 수집 "num_inc_gc": 8, // 얼마나 많은 증분 쓰레기 수집 "heap_compactions": 8, // 기존 생성이 몇 번이나 정렬되는지 "2592568, // 추정 된 카테인 레탈" 2499912, // 최소 "max": 2592568, // 최대 "usage_trend": 0 // 사용자 트렌드}NUM_FULL_GC 및 NUM_INC_GC를 관찰하십시오.
누출 이벤트 : 5 번의 연속 쓰레기 수집 후에 메모리가 아직 해제되지 않으면 메모리 누출이 발생 함을 의미합니다. 이번에는 누출 이벤트가 트리거됩니다.
{스타트 : Fri, 29 2012 년 6 월 29 일 14:12:13 GMT, END : FRI, 29 2012 년 6 월 29 일 14:12:33 GMT, 성장 : 67984, 이유 : '5 연속 GC (20S)에 걸쳐 힙 성장 -1167MB/HR'}힙 디프트 힙 메모리 비교 문제 해결 메모리 오버 플로우 코드.
아래에서 예제를 사용하여 메모리 누출 문제를 해결하는 방법을 보여줍니다.
먼저 메모리 누출을 일으키는 예제를 만듭니다.
//app.jsvar app = require ( 'express') (); var http = require ( 'http'). server (app); var heapdump = require ( 'heapdump'); var leakobjs = []; function LeakClass () {this.x = 1;} app.get ( '/', res (req, res); 0; i <1000; leakobjs.push ( '<h1> hello world </h1>'); 3000); http.listen (3000, function () {console.log ( '포트 3000에서 듣기');});여기서 우리는 지속적으로 증가하고 검색되지 않는 배열을 설정하여 메모리 누출을 시뮬레이션합니다.
힙 덤프 모듈을 사용하여 메모리 스냅 샷을 정기적으로 기록하고 크롬 개발자 도구 프로파일을 통해 스냅 샷을 가져 오기 위해 비교 및 분석을 위해 스냅 샷을 가져옵니다.
브라우저가 LocalHost : 3000에 액세스하고 여러 번 새로 고침 된 후 스냅 샷의 크기가 커지고 있으며 요청되지 않더라도 감소하지 않아 누출이 발생했음을 알 수 있습니다.
그런 다음 Chrome 개발자 도구 프로파일을 통해 스냅 샷을 가져옵니다. 비교를 설정하면 초기 스냅 샷을 비교하고 요청을 보내고 요청을 보내서이 세 단계에서 메모리 스냅 샷을 보냅니다. 오른쪽의 새 신자가 LeakClass가 증가하고 있음을 알 수 있습니다. 델타에서는 항상 긍정적이므로 재활용되지 않았 음을 의미합니다.
요약
메모리 누출의 경우 Memwatch를 사용하여 임플란트를 사용하거나 프로세스를보고 할 수 있습니다 .MemoryUsage 메모리 사용을 정기적으로 모니터링하고 모니터링을위한 경보 임계 값을 설정하십시오.
메모리 누출이 발견되면 허용되면 Node-HeapDump를 로컬로 실행하고 시간이 지정된 메모리 스냅 샷을 사용하여 생성 할 수 있습니다. 스냅 샷을 사용하여 크롬 프로파일을 통한 누출 원인을 분석하십시오. 로컬 디버깅이 불가능한 경우 V8-Profiler를 사용하여 테스트 서버의 메모리 스냅 샷을 출력하여 JSON을 비교하고 분석하십시오 (코드 침입이 필요).
어떤 상황에서 고려해야 할 상황에서 Memwatch/HeepDump가 활성화됩니다. CPU가 떨어지지 않도록 힙의 주파수를 고려하십시오. 직접 모니터링 프로세스 .memoryUsage ()와 같은 메모리 성장을 감지하는 다른 방법도 고려할 수 있습니다.
잘못 판단하면 단기 메모리 사용 피크는 메모리 누출처럼 행동합니다. 앱이 갑자기 많은 CPU와 메모리를 소비하면 처리 시간이 여러 쓰레기 수집주기에 걸쳐있을 수 있으며 Memwatch는 메모리 누출로 판단 할 수 있습니다. 그러나이 경우 앱이 이러한 리소스를 사용하면 메모리 소비가 정상 수준으로 떨어집니다. 따라서 메모리 누출이 지속적으로보고되고 한두 번의 갑작스런 경보를 무시할 수 있습니다.