추천 튜토리얼: "JavaScript Video Tutorial"
최근 인터뷰 리뷰를 봤는데, 그 중 많은 사람들이 면접관으로부터 JS 가비지 수집 메커니즘에 대해 이야기해 달라는 요청을 받았습니다. 솔직히 말해서 면접관은 이렇게 묻습니다. 질문 및 설명 그는 최근 JS 가비지 수집 메커니즘에 대한 관련 기사를 보았고 B 그리드를 위해 지나가면서 질문했습니다.
최근 JS 가비지 컬렉션에 관한 외국 기사를 보았는데, 명확하게 설명되어 있어서 도움이 되셨으면 좋겠습니다.
JavaScript의 메모리 관리는 자동으로 수행되며 눈에 보이지 않습니다. 우리는 메모리가 필요한 기본 유형, 객체, 함수 등을 만듭니다.
무언가가 더 이상 필요하지 않으면 어떻게 되나요? JavaScript 엔진은 이를 어떻게 찾아서 정리합니까?
JavaScript의 메모리 관리의 주요 개념은 도달 가능성입니다.
간단히 말해서 "접근성" 값은 메모리에 저장되는 것이 보장되는 어떤 방식으로든 액세스하거나 사용할 수 있는 값입니다.
1. 명백한 이유로 삭제할 수 없는 본질적으로 도달 가능한 기본 값 집합이 있습니다. 예:
로컬 함수의 로컬 변수 및 매개변수
현재 중첩 호출 체인에 있는 다른 함수의 변수 및 매개변수
전역 변수
다른 내부 변수도 있습니다.
이러한 값을 루트라고 합니다.
2. 참조 또는 참조 체인이 루트에서 액세스할 수 있는 경우 다른 값은 액세스 가능한 것으로 간주됩니다.
예를 들어, 지역 변수에 객체가 있고, 그 객체가 다른 객체를 참조하는 속성을 갖고 있다면, 그 객체는 도달 가능하다고 간주되고, 참조하는 객체도 접근 가능하다면, 자세한 예시는 다음과 같습니다.
JavaScript 엔진에는 Garbage Collector라는 백그라운드 프로세스가 있는데, 이 프로세스는 모든 개체를 모니터링하고 액세스할 수 없는 개체를 삭제합니다.
다음은 가장 간단한 예입니다.
// user 具有对象的引用 let user = { name: "John" };
여기서 화살표는 개체 참조를 나타냅니다. 전역 변수 "user"
는 {name: "John"}
개체를 참조합니다(간결함을 위해 이름을 “user”
引用对象 {name:“John”}
(为了简洁起见,我们将其命名为John)。John 的 “name”
属性存储一个基本类型,因此它被绘制在对象中。
如果 user
的值被覆盖,则引用丢失:
user = null;
现在 John 变成不可达的状态,没有办法访问它,没有对它的引用。垃圾回收器将丢弃 John 数据并释放内存。
现在让我们假设我们将引用从 user
复制到 admin
:
// user具有对象的引用 let user = { name: "John" }; let admin = user;
现在如果我们做同样的事情:
user = null;
该对象仍然可以通过 admin
全局变量访问,所以它在内存中。如果我们也覆盖admin
,那么它可以被释放。
现在来看一个更复杂的例子, family 对象:
function marry (man, woman) { woman.husban = man; man.wife = woman; return { father: man, mother: woman } } let family = marry({ name: "John" }, { name: "Ann" })
函数 marry
John
"name"
속성은 기본 유형을 저장하여 객체에 그려집니다. user
값을 덮어쓰면 참조가 손실됩니다: delete family.father; delete family.mother.husband;
이제
John에 접근할 수 없게 되어 접근할 방법도 없고 그에 대한 참조도 없습니다. 가비지 수집기는
John데이터를 삭제하고 메모리를 확보합니다.
두 개의 참조이제user
에서 admin
으로 참조를 복사한다고 가정해 보겠습니다.family = null;
rrreee객체는 여전히 전달될 수 있습니다 admin 전역 변수 액세스이므로 메모리에 있습니다. admin
도 덮어쓰면 해제될 수 있습니다.
상호 연관된 객체이제 좀 더 복잡한 예인 family 객체를 살펴보겠습니다.
rrreee marry
함수는 두 객체에 서로에 대한 참조를 제공하여 "결혼"하고 A new를 포함하는 객체를 반환합니다. 두 개체 모두에 대한 개체입니다.
결과 메모리 구조:
지금까지 모든 개체에 액세스할 수 있습니다.
이제 두 참조를 모두 삭제해 보겠습니다.
rrreee🎜🎜 모든 개체에 계속 액세스할 수 있으므로 이 두 참조 중 하나만 삭제하는 것만으로는 충분하지 않습니다. 🎜🎜그러나 둘 다 제거하면 🎜John🎜에 더 이상 들어오는 참조가 없음을 알 수 있습니다. 🎜🎜🎜🎜🎜나가는 참조는 중요하지 않습니다. 전달된 객체만 객체에 액세스할 수 있게 하므로 이제 🎜John🎜에 액세스할 수 없으며 액세스할 수 없는 모든 데이터는 메모리에서 제거됩니다. 🎜🎜가비지 수집 후: 🎜🎜🎜🎜🎜접속할 수 없는 데이터 블록 🎜🎜상호 연결된 전체 개체에 액세스할 수 없게 되고 메모리에서 삭제될 수 있습니다. 🎜🎜소스 객체는 위와 동일합니다. 그럼:🎜rrreee🎜추억 속의 사진은:🎜이 예는 접근성 개념이 얼마나 중요한지 보여줍니다.
분명히 John과 Ann은 여전히 함께 연결되어 있으며 둘 다 참조가 수신됩니다. 그러나 이것만으로는 충분하지 않습니다.
"패밀리" 개체가 루트에서 연결 해제되어 더 이상 참조가 없으므로 아래 전체 블록에 접근할 수 없게 되어 삭제됩니다.
기본 가비지 수집 알고리즘은 "Mark-Sweep"이라고 하며 다음과 같은 "가비지 수집" 단계를 주기적으로 수행합니다.
가비지 수집기는 루트와 "marks"를 가져옵니다( ) 그들을 .
그런 다음 해당 참조의 모든 참조에 액세스하고 "태그"를 지정합니다.
그런 다음 표시된 개체에 액세스하고 해당 참조를 표시합니다. 접근된 모든 객체는 기억되어 향후 동일한 객체에 두 번 접근하지 않습니다.
방문하지 않은 참조가 있을 때까지 계속됩니다(루트에서 액세스 가능).
표시된 개체를 제외한 모든 개체가 삭제됩니다.
예를 들어 객체 구조는 다음과 같습니다.
오른쪽에 "접근할 수 없는 블록"이 있는 것을 확실히 볼 수 있습니다. 이제 "Mark and Sweep" 가비지 수집기가 이를 어떻게 처리하는지 살펴보겠습니다.
첫 번째 단계는 루트
를 표시한 다음 해당 참조
및 하위 항목의 참조를 표시하는 것입니다.
프로세스에서 액세스할 수 없는 개체는 이제 액세스할 수 없는 것으로 간주되어 삭제됩니다.
가비지 수집이 작동하는 방식입니다. JavaScript 엔진은 실행에 영향을 주지 않고 더 빠르게 실행되도록 많은 최적화를 적용합니다.
일부 최적화:
세대 재활용 - 개체는 "새 개체"와 "오래된 개체"라는 두 그룹으로 나뉩니다. 많은 개체가 나타나 작업을 완료하고 빠르게 종료되며 빠르게 정리됩니다. 충분히 오래 사는 사람들은 "늙어가고" 검사를 거의 받지 않습니다.
증분적 재활용 - 객체가 많고 전체 객체 세트를 한 번에 탐색하고 표시하려고 하면 시간이 좀 걸리고 실행이 약간 지연될 수 있습니다. 따라서 엔진은 가비지 수집을 여러 부분으로 나누려고 시도합니다. 그런 다음 각 부분이 별도로 실행됩니다. 변경 사항을 추적하려면 추가 마커가 필요하므로 큰 지연이 아닌 작은 지연이 많이 발생합니다.
Idle Time Collection - 가비지 수집기는 실행에 미칠 수 있는 영향을 줄이기 위해 CPU가 유휴 상태일 때만 실행됩니다.
1) 쓰레기가 무엇인지 물어보세요
일반적으로 참조되지 않은 객체는 가비지이므로 삭제해야 하는 객체는 여러 객체 참조가 링을 형성하여 참조하는 경우입니다. 그러나 루트는 이러한 개체에 액세스할 수 없습니다. 이러한 개체도 가비지이므로 지워야 합니다.
2) 쓰레기 확인 방법
한 가지 알고리즘은 mark-clear 알고리즘입니다. 다른 알고리즘에 대해서도 이야기하고 싶습니다. 여기를 참조하세요.
더 자세한 설명 V8 Journey: Garbage Collector
더 많은 프로그래밍 관련 지식을 보려면 프로그래밍 소개를 방문하세요! !
위 내용은 JavaScript의 가비지 수집 메커니즘 이해의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!