웹에서의 메모리 누수(Memory Leak)

2019-11-19


회사에서 메모리 누수와 관련되어 테스트를 하게 되면서 메모리 누수는 무엇이고 어떤 이유로 발생하는지 공부한것을 정리했다.

자바스크립트에서 메모리 누수

메모리 누수는 페이지(어플리케이션)에서 더 이상 사용되지 않는 메모리가 어떤 이유로 회수되지 않고 불 필요하게 남아있는 현상으로 설명될 수 있다. 코드에서 객체나 변수를 생성하면 메모리가 소모된다. 자바스크립트는 알아서 더 이상 사용되지 않는 변수를 파악하고 회수함으로써 메모리를 절약한다.

메모리 누수는 실제로는 더 이상 사용되지 않는 메모리가 자바스크립트 런타임에서는 필요하다고 판단해 회수되지 않고 남아있는 현상이다. 이는 작업을 수행하는 데 사용할 수 있는 메모리의 양을 감소시켜 어플리케이션의 성능이 저하되고 결국 충돌이나 정지로 이어질 수 있다.

메모리 문제 발견하기

자바스크립트에서의 메모리

자바스크립트는 객체가 생성 되었을 때 자동으로 메모리를 할당하고 쓸모 없어 졌을 때 가비지 콜렉션으로 자동으로 해제한다.

  1. 필요할 때 할당한다 (변수, 함수의 정의)
  2. 사용한다 (변수혹은 객체를 읽거나 쓴다, 함수에 인자를 넘겨준다)
  3. 필요 없어지면 해제한다 (태스크가 완료되고 할당된 메모리가 더 이상 필요 없을 때)

여기에서 할당된 메모리가 더 이상 필요 없을 때 를 알아내기는 쉽지 않다. 자바스크립트와 같은 고수준 언어들은 자동 메모리 관리 방법을 사용하는데 이는 가비지 콜렉터가 메모리 할당을 추적하고 할당된 메모리 블록이 더 이상 필요하지 않게 되었는지를 판단하여 회수한다.

가비지 컬렉션 이란? (GC)

가비지 컬렉터는 알고리즘을 통해 페이지나 어플리케이션내에서 더 이상 필요없어진 메모리를 찾아내고 회수한다. 가비지 컬렉션의 방식은 매우 효과적이지만, 여전히 자바스크립트 메모리 누수가 발생할 수 있다. 메모리 누수가 발생하는 가장 큰 이유 원치 않는 참조에 의한 경우가 많다. 가비지 콜렉션 프로세스는 추측에 기반 하기 때문에 메모리를 회수해야 하는지에 대한 복잡한 문제는 매번 알고리즘에 의해 올바르게 결정될 수 없기 때문이다.

메모리 누수가 일어날 수 있는 패턴

예측하지 못한 전역 변수

선언되지 않은 변수를 참조하면 이는 자동적으로 전역 변수로 생성된다. 코드의 시작에 'use strict'를 써 스트릭 모드를 사용하면 전역변수를 허용하지 않아 전역변수의 사용을 미리 예방 할 수 있다.

명시적으로 사용된 전역변수는 (null처리 되거나 재할당되지 않는 한) 회수할 수 없다는 의미를 가진다. 특히 일시적으로 사용 되거나 큰 규모의 데이터를 저장하는 데 사용되는 전역 변수들이 문제를 일으킬 수 있다. 이러한 상황에 전역변수를 사용해야 한다면, 사용 된 후에는 반드시 null처리 해주거나 재할당해주는 것이 좋다.

클로저

함수가 외부 스코프의 변수를 기억하는 것을 클로저라고 한다. 어떤 외부함수에서 내부 함수를 반환할때 외부 함수에 변수를 참조하게되면 이 변수는 외부 함수의 실행이 끝난뒤에도 사라지지 않고 값을 기억하게 된다. 클로저가 이 변수(환경)를 기억하기 위해서는 메모리가 필요하고 이 메모리는 참조를 제거하지 않는 한 GC에 의해 회수되지 않을 것이다.

DOM을 벗어난 참조

Detached DOM은 DOM에서는 지워졌지만 자바스크립트에 의해 여전히 메모리를 차지하고 있는 경우를 말한다. DOM요소가 코드내에서 변수나 객체에 의해 참조되고 있으면 DOM내에서 삭제되어도 GC에 의해 회수되지 않는다.

이벤트 리스너

addEventListner()메서드에 연결되는 DOM요소의 수명이 일치하지 않으면 메모리 누수로 이어질 수 있다.


그동안 공부하거나 토이프로젝트등을 할때는 메모리에 대해 크게 생각해 보지 않았는데, (잘 모르기도 했고), 실제로 업무에서 이슈를 겪으면서 메모리 누수가 무엇이고 왜 일어나는지 알아볼 수 있었고 사전에 방지하지 않으면 언제 어떤일이 생길지 모를 수 있다?는 것을 배웠다.

메모리 프로파일링이나 타임라인등 크롬 데브툴을 통해 개발단계에서도 주기적으로 메모리 누수를 확인하도록 하자.

참고 글

https://www.lambdatest.com/blog/eradicating-memory-leaks-in-javascript/

https://developers.google.com/web/tools/chrome-devtools/memory-problems