>웹 프론트엔드 >JS 튜토리얼 >JavaScript 및 그 이후의 가비지 수집 이해

JavaScript 및 그 이후의 가비지 수집 이해

Susan Sarandon
Susan Sarandon원래의
2025-01-27 22:32:17572검색

Understanding Garbage Collection in JavaScript and Beyond

최근 기술 인터뷰에서 다양한 프로그래밍 언어가 가비지 수집을 어떻게 처리하는지 질문을 받았습니다. 이것은 놀랍지만 신선한 질문이었고, 정말 내 관심을 불러일으켰습니다. 이전 인터뷰에서 메모리 관리에 대해 이렇게 깊이 있게 논의한 적이 없었습니다. 나는 이 질문을 좋아하며 블로그 게시물에서 이 주제를 더 자세히 살펴보고 싶습니다.


고성능 애플리케이션에는 효율적인 메모리 관리가 중요합니다. 가비지 수집(GC) 메모리 누수 및 충돌을 방지하기 위해 사용하지 않는 메모리를 자동으로 재활용합니다. 이 기사에서는 JavaScript에서 가비지 수집이 작동하는 방식에 초점을 맞추고 프로그래밍 언어에서 사용되는 다른 방법을 살펴보고 이러한 개념을 설명하는 예제를 제공합니다.


가비지 컬렉션이란 무엇인가요?

가비지 수집은 더 이상 사용되지 않는 개체가 차지하는 메모리를 회수하는 프로세스입니다. 자동 가비지 수집 기능이 있는 언어는 이 프로세스를 추상화하므로 개발자가 수동으로 메모리를 관리할 필요가 없습니다. 예를 들어 JavaScript는 추적 가비지 수집기를 사용하는 반면 다른 언어는 다른 기술을 사용합니다.


JavaScript의 가비지 수집

JavaScript는 가비지 수집 추적 방법, 특히 mark-sweep 알고리즘을 사용합니다. 분석해 보겠습니다.

1. 마크 클리어 알고리즘

이 알고리즘은 메모리에서 "연결 가능한" 개체를 확인하고 연결할 수 없는 개체를 해제합니다.

  1. 마크 스테이지:
    • "루트" 개체에서 시작합니다(예: 브라우저의 window 또는 Node.js의 전역 개체).
    • 이러한 루트 개체에서 연결할 수 있는 모든 개체를 반복하고 "활성"으로 표시합니다.
  2. 클리어 페이즈:
    • 힙을 스캔하고 도달 가능으로 표시되지 않은 객체를 해제합니다.

예:

<code class="language-javascript">function example() {
  let obj = { key: "value" }; // obj 可达
  let anotherObj = obj; // anotherObj 引用 obj

  anotherObj = null; // 引用计数减少
  obj = null; // 引用计数减少到 0
  // obj 现在不可达,将被垃圾回收
}</code>

2. 세대별 가비지 수집

최신 JavaScript 엔진(예: Chrome/Node.js의 V8)은 세대 GC를 사용하여 가비지 수집을 최적화합니다. 메모리는 다음과 같이 구분됩니다.

  • 신세대: 수명이 짧은 개체(예: 함수 범위 변수)가 여기에 저장되고 자주 수집됩니다.
  • Old Generation: 수명이 긴 개체(예: 전역 변수)가 여기에 저장되며 덜 자주 수집됩니다.

세대별 GC가 더 효율적인 이유는 무엇인가요?

  • JavaScript의 대부분의 개체는 임시적이며 빠르게 수집할 수 있습니다.
  • 수명이 긴 객체는 Old Generation으로 이동되므로 자주 검사할 필요성이 줄어듭니다.

기타 쓰레기 수거 전략

다른 언어에서 가비지 수집을 처리하는 방법을 살펴보겠습니다.

1. 참조 횟수

참조 카운팅은 객체를 가리키는 참조 수를 추적합니다. 참조 횟수가 0으로 떨어지면 객체가 해제됩니다.

장점:

  • 간단하고 즉각적인 메모리 회수.
  • 예상대로 행동합니다.

단점:

  • 순환 참조: 두 객체가 서로 참조하는 경우 해당 개수는 절대 0에 도달하지 않습니다.

예: (Python 참조 카운팅)

<code class="language-javascript">function example() {
  let obj = { key: "value" }; // obj 可达
  let anotherObj = obj; // anotherObj 引用 obj

  anotherObj = null; // 引用计数减少
  obj = null; // 引用计数减少到 0
  // obj 现在不可达,将被垃圾回收
}</code>

2. 수동 메모리 관리

CC 와 같은 언어에서는 개발자가 명시적으로 메모리를 할당하고 해제해야 합니다.

예: (C 메모리 관리)

<code class="language-python">a = []
b = []
a.append(b)
b.append(a)
# 这些对象相互引用,但不可达;现代 Python 的循环收集器可以处理这种情况。</code>

장점:

  • 메모리 사용량을 완전히 제어할 수 있습니다.

단점:

  • 메모리 누수(메모리 해제를 잊어버림) 및 매달린 포인터(조기 메모리 해제)가 발생하기 쉽습니다.

3. 루프 수집기로 가비지 수집 추적

Python과 같은 일부 언어에서는 참조 계산주기 감지를 결합하여 순환 참조를 처리합니다.

  • 루프 수집기는 주기적으로 개체를 검색하여 루프(루트 개체에서 액세스할 수 없는 상호 참조 개체 그룹)를 감지합니다. 루프가 발견되면 수집기는 이를 중단하고 메모리를 회수합니다.
  • 순환 컬렉터는 순수 참조 카운팅(순환 참조)의 가장 큰 단점을 해결합니다. 추가 오버헤드를 추가하지만 루프로 인해 메모리 누수가 발생하지 않도록 합니다.

4. Rust의 빌림 검사기(GC 없음)

Rust는 가비지 수집을 완전히 피하는 다른 접근 방식을 취합니다. 대신 Rust는 Borrow Checker를 통해 엄격한 소유권 규칙을 시행합니다.

  • 소유권: 각 값에는 한 번에 한 명의 소유자만 있습니다.
  • 차용: 참조(불변 또는 변경 가능)를 빌릴 수 있지만 데이터 경합을 방지하기 위해 한 번에 하나의 변경 가능한 참조만 허용됩니다.
  • 수명주기: 컴파일러는 값이 범위를 벗어나는 경우를 추론하고 자동으로 메모리를 해제합니다.

이 시스템은 기존 GC가 필요 없이 메모리 안전을 보장하여 Rust에 수동 메모리 관리의 성능 이점을 제공하는 동시에 매달린 포인터와 같은 일반적인 실수를 방지하는 데 도움을 줍니다.

추가설명. #데이터 경합은 두 개 이상의 스레드(또는 프로세스)가 동시에 동일한 메모리 위치에 액세스하고 하나 이상의 스레드가 해당 위치에 쓸 때 동시 또는 병렬 프로그래밍에서 발생합니다. 이러한 동시 액세스를 조정하는 메커니즘(예: 잠금 또는 원자적 작업)이 없기 때문에 공유 데이터의 최종 상태는 예측할 수 없고 일관성이 없으므로 오류를 찾기 어려울 수 있습니다.


가비지 수집 전략 비교

方法 语言 优点 缺点
引用计数 早期的 Python,Objective-C 立即回收,易于实现 循环引用失效
追踪式(标记-清除) JavaScript,Java 处理循环引用,对于大型堆效率高 停止世界暂停
分代式 GC JavaScript,Java 针对短暂的对象进行了优化 实现更复杂
手动管理 C,C 完全控制 容易出错,需要仔细处理
混合式(引用计数 循环收集器) 现代 Python 两全其美 仍然需要定期的循环检测
借用检查器 Rust 无需 GC,防止数据竞争 学习曲线较陡峭,所有权规则
---

JavaScript가 일반적인 시나리오를 처리하는 방법

참고문헌

JavaScript의 추적 가비지 수집기는 순환 참조를 매우 잘 처리합니다.

<code class="language-javascript">function example() {
  let obj = { key: "value" }; // obj 可达
  let anotherObj = obj; // anotherObj 引用 obj

  anotherObj = null; // 引用计数减少
  obj = null; // 引用计数减少到 0
  // obj 现在不可达,将被垃圾回收
}</code>

이벤트 리스너 및 종료

이벤트 리스너가 제대로 정리되지 않으면 실수로 메모리 누수가 발생할 수 있습니다.

<code class="language-python">a = []
b = []
a.append(b)
b.append(a)
# 这些对象相互引用,但不可达;现代 Python 的循环收集器可以处理这种情况。</code>

핵심요약

  1. JavaScript는 mark-sweep 알고리즘과 함께 추적 가비지 수집기를 사용하여 메모리를 자동으로 관리합니다.
  2. 세대 GC는 임시 객체에 초점을 맞춰 성능을 최적화합니다.
  3. 다른 언어는 다른 전략을 사용합니다.
    • 참조 카운팅: 단순하지만 순환 참조가 발생하기 쉽습니다.
    • 수동 관리: 완전한 제어가 가능하지만 오류가 발생하기 쉽습니다.
    • 하이브리드 접근 방식: 더 나은 성과를 위해 전략을 결합합니다.
    • Rust의 빌림 검사기 : GC는 없지만 소유권 규칙이 엄격합니다.
  4. 특히 클로저와 이벤트 리스너에서 JavaScript의 잠재적인 메모리 누수에 주의하세요.

이것은 언어가 가비지 수집에 사용하는 전략에 대한 통찰력을 얻을 수 있는 좋은 기회입니다. 나는 가비지 수집이 어떻게 작동하는지 이해하면 효율적인 코드를 작성하는 데 도움이 될 뿐만 아니라 메모리 관련 오류를 효과적으로 디버깅할 수 있다고 믿습니다.


참고자료

  • JavaScript 및 메모리 관리: MDN 문서
  • V8 가비지 컬렉션: 가비지 컬렉션에 대한 V8 블로그
  • Rust의 소유권: The Rust 프로그래밍 언어 도서
  • Java 가비지 수집: Oracle 설명서
  • Python의 GC: Python gc 모듈

위 내용은 JavaScript 및 그 이후의 가비지 수집 이해의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

성명:
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.
이전 기사:Javascript의 범위.다음 기사:Javascript의 범위.