새오의 개발 기록

Javascript: 가비지 컬렉터 본문

Javascript

Javascript: 가비지 컬렉터

새오: 2023. 1. 25. 16:10
출처: Udemy 자바스크립트 완벽 가이드

 

 

 

 

 

메모리 관리의 필요성

 

 

 

  • 오버플로우가 될 수 있으니 메모리가 관리되는 것은 중요함
  • 컴퓨터 또는 머신의 운영 체제는 Chrome에 일정량의 메모리만을 할당하고 만약 이를 초과할 경우 Chrome을 종료시키도록 되어 있는데 Chrome이 내부 메모리 관리를 해서 메모리를 많이 차지하기 전에 웹사이트를 종료하기 때문에 실제로 이런 일은 절대 일어나지 않음.
  • 따라서 웬만한 상황에서는 메모리를 우리가 직접 관리할 필요가 없음
 

 

 

 

 

가비지 컬렉터

 

 

  • Chrome이 메모리를 관리하는 방식으로 모든 JavaScript 엔진이 갖고 있음

 

 

가비지 컬렉터의 역할

 

 

  • 사용되지 않은 객체, 즉 참조되지 않은 객체에 대한 힙 메모리를 주기적으로 확인함
  • 참조란 결국에 변수에 저장된 주소이며 가비지 컬렉터는 사용되지 않은 객체를 메모리에서 제거함.
  • 힙 메모리에서 제거되며 확인된 모든 객체는 더는 코드에서 동작하지 않음.

 

 

 

 

let person = {name: 'Max'};

person = null;

 

 

  • person 객체는 Max라는 이름을 가지는 참조 값이며 힙에 저장됩니다
  • 이 변수를 가지고 있는 한 person 변수는 객체의 주소를 가지게 되며 JavaScript는 객체에 대한 참조를 갖게됨
  • 이 경우에, JavaScript는 메모리에서 객체를 제거하지 않음.
  • person을 null로 저장하자마자 가비지 컬렉터가 작동하는데, 이 변수에 새로운 값을 할당하면 여기 객체가 스크립트에서 더는 참조되지 않게 되기 때문임.
  • 코드에 있는 어떤 변수 또는 어떤 곳에서도 객체를 참조하지 않기 때문에 제거할 수 있음
  • 객체와 또 다른 객체인 배열 등은 let 또는 const로 만들어진 변수에 저장되고 스크립트 내에서 변수를 계속 사용하지 않는다면 변수를 제거하기 위해 null로 설정할 필요가 없음. 가비지 컬렉터가 찾아내어 제거할 것임.
    • 즉각적으로 제거하지는 않지만 자체 스케줄에 따라서 결국에는 이들을 확인하여 메모리에서 제거됨.
 

 

 

 

 

 

메모리 누수

 

 

코드를 작성할 때 더는 동작하지 않는 객체가 있고 여전히 이를 참조하고 있다면  가비지 컬렉션을 진행할 수 없음

-> 코드에 버그 있는 것 

 

 

 

정상적인 경우

 

const addListenerBtn = document.getElementById('add-listener-btn');
const clickableBtn = document.getElementById('clickable-btn');
const messageInput = document.getElementById('click-message-input');

function printMessage() {
  const value = messageInput.value;
  console.log(value || 'Clicked me!');
}

function addListener() {
  clickableBtn.addEventListener('click', printMessage);
}

addListenerBtn.addEventListener('click', addListener);

 

  • 2개의 이벤트 리스너가 있으며 이 끝에 있는 이벤트 리스너는 스크립트가 실행될 때 실행함
  • Click me 버튼은 다른 버튼을 클릭했을 때만 이벤트 리스너를 가져옴(printMessage())
  • Click me를 클릭해도 콘솔에 아무것도 나타나지 않고 Add a listener를 클릭하고 Click me를 클릭하면 결괏값이 나옴
  • Add a listener 버튼을 클릭할 때마다 Click me 버튼에 계속 리스너를 추가하여 클릭할 때마다 이 함수가 더 많이 실행한다고 생각할 수 있지만 그렇지 않음. 한 번만 동작함
    • 그 이유는 버튼에 이벤트 리스너를 추가하는 경우 또는 어떤 요소에 이벤트 리스너를 연결하여 이전에 사용한 함수를 호출하는 경우에, JavaScript가 새로운 리스너를 만드는 대신에 기존 리스너를 새로운 리스너로 교체하기 때문
    • 그렇지 않다면 같은 객체에 수백 개의 리스너가 연결될 수도 있고 이는 원하지 않는 행동을 발생시킬 가능성이 있고 메모리 누수를 야기할 수 있음
    • 이 모든 함수로 메모리를 차지하게 되고 함수는 객체와 마찬가지이므로 힙 메모리에 저장되고 시간이 지남에 따라 메모리를 꽉 채우기 때문에 브라우저가 이를 허용하지 않는 것은 좋은 일

 

 

 

 

비 정상적인 경우

 

const addListenerBtn = document.getElementById('add-listener-btn');
const clickableBtn = document.getElementById('clickable-btn');
const messageInput = document.getElementById('click-message-input');

function printMessage() {
  const value = messageInput.value;
  console.log(value || 'Clicked me!');
}

// 익명함수로 변경함
function addListener() {
  clickableBtn.addEventListener('click', function() {
  const value = messageInput.value;
  console.log(value || 'Clicked me!');
  });
}

addListenerBtn.addEventListener('click', addListener);

 

  • 익명함수로 변경
  • 이름을 할당하지 않지만 메모리에 여전히 저장되고 이 함수의 포인터는, 즉 함수의 주소는 이벤트 리스너의 두 번째 인자로 전달되며 이 함수는 즉석에서 만들어짐
  • 즉시 실행되거나 하지는 않지만 pringMessage를 가리킬 때와 똑같이 행동함
  • 차이점은, 함수에 이름이 없고 addListener가 실행할 때마다 새로운 객체로 생성된다는 것. 이 함수는 즉석에서 만들어짐
  • 이전에 printMessage 함수는 전체 스크립트가 실행될 때 처음 한 번만 만들어졌고 그 후에 절대 다시 실행되지 않으며 하나의 함수 객체만 만들어짐. 여기서는 addListener가 실행될 때마다 새로 만들어짐
  • addListener를 실행할 때마다 새 함수를 만들기 때문에 메모리 누수를 야기할 수 있고 수십, 수백 개의 함수 객체를 메모리에 가져오고 JavaScript는 이를 제거할 수 없음
  • 이는 의도적으로 만든 상황이며 대부분 발생하지 않음

 

 

 

 

 

 

 

'Javascript' 카테고리의 다른 글

Javascript: 원시 vs 참조값  (0) 2023.01.25
Javascript: 코드 실행의 원리(힙, 스택)  (1) 2023.01.25
Javascript: 코드의 분석과 컴파일링  (0) 2023.01.25
Javascript: ES6와 ES6의 차이  (0) 2023.01.25
Javascript: Math.floor()  (0) 2023.01.19