WeakRef 및 constorelog
25409 단어 JavaScripttech
tl;dr
console.log
에서 참조console.log
도 참조로 사용하기 때문에 원래 개방해야 한다고 해도 자원이 개방되지 않는다확인한 일
순환 참조 대상인 GC가 만들어지지 않아 난감해하지 않기 때문에 이것저것 확인하기 위해 실험하고 있다.
우선 순환 인용 대상을 만듭니다.이 노드는parent와children 사이에서 서로 참조됩니다.
크롬의 메모리 프로필을 보고 싶어서 vite가 어지럽게 만들어진 환경에서 다음 코드를 실행합니다.
const app = document.querySelector<HTMLDivElement>("#app")!;
class Node {
public children: Node[] = [];
constructor(public parent: Node | null, public value: string) {}
}
function createCircularObject(parent: Node | null, depth: number): Node {
const n: Node = new Node(parent, Math.random().toString(32));
if (depth > 0) {
[...Array(30).keys()].map(() => {
const newNode = createCircularObject(n, depth - 1);
n.children.push(newNode);
});
}
return n;
}
const button = document.createElement("button");
let cnt = 0;
button.textContent = "start";
button.addEventListener("click", () => {
const n = createCircularObject(null, 3);
console.log("round:", cnt, n);
});
app.appendChild(button);
export {};
버튼은 순환 참조 객체를 생성합니다.Chrome DevTools에서 Memory Tab을 열고 여기서 버튼을 몇 번 눌러 보세요.다음 그림은 다시 불러온 후에 한 번, 두 번 단추를 누르십시오.이후 메모리 프로세서를 다시 시작하는 데 시간을 조금 더 두십시오.
실행할 때마다 약 1.75M의 메모리가 누출된다.
여기에 의문이 하나 있다.v8의 세대별 GC의 경우 내부에 순환 참조가 발생하더라도 한 대상의 내부를 닫고 루트 요소가 외부에 참고되지 않으면 메모리가 표시되지 않고 회수된다는 가설이 있다. 그러나 아무리 해도 이렇게 움직이지 않는다.
여기서 갑자기 콘솔이 생각났어요.로그를 끄려고 하자 메모리가 열렸다.
즉, Dev Tools를 열 때 console을 사용합니다.로그로 표시된 내용 자체가 참조이다.자세히 생각해 보면 당연한 것이고, DevTools는 검사기로 대상을 차례로 펼칠 수 있다.window.parent.parent.Parent처럼 접근할 수 있는 건 그것 때문이야.
WeakRef 사용
이번 주제에는 ES2021이 WeakRef에 합류했다.IE 이외에는 대부분 사용할 수 있다.https://caniuse.com/?search=WeakRef
WeakRef는 비고정 참조
const ref = new WeakRef(obj);
로 참조를 만들고 ref.deref()
로 참조를 반환합니다.GC가 참조자를 폐기하면 undefined가 반환됩니다.GC를 간접적으로 관측할 수 있다는 것이다.WeakRef 자체 참조 영역은 표식 및 스윕의 표식이 되지 않습니다.옷장이 있는 자바스크립트에서는 언어 규범에 의도하지 않은 인용을 방지하기 어렵다, 콘솔.로그를 제외하고는 때때로 조심하지 않아 참고를 남기기도 한다.특히 전단에서는 가동 트리거가 제대로 개방됐는지 확인하기 어렵다.(TS에 Rust를 넣은 생명시간이 이렇게 격렬하게 변경된다면 가능할 텐데...)
이에 따라 이번에는 위크레프에서 약한 참조로 회피할 수 있는지 검증했다.
const app = document.querySelector<HTMLDivElement>("#app")!;
class MyNode {
public children: WeakRef<MyNode>[] = [];
constructor(public parent: WeakRef<MyNode> | null, public value: string) {}
}
function createCircularObject(
parent: WeakRef<MyNode> | null,
depth: number
): MyNode {
const n: MyNode = new MyNode(parent, Math.random().toString(32));
if (depth > 0) {
[...Array(30).keys()].map(() => {
const newNode = createCircularObject(new WeakRef(n), depth - 1);
const newRef = new WeakRef(newNode);
n.children.push(newRef);
});
}
return n;
}
const button = document.createElement("button");
let cnt = 0;
button.textContent = "start";
button.addEventListener("click", () => {
const n = createCircularObject(null, 3);
console.log("round:", cnt++, n);
});
app.appendChild(button);
console.로그가 장악한 것이기 때문에 뿌리 요소의 MyNode가 하나하나 새어나온다.하지만 그 외에는 모두 발매됐다.
추기
그리고 위의 코드를 자세히 보면 틀렸어요. 칠드렌에 대한 참조는 weakRef만 통과했기 때문에 다음 GC에서는 뿌리 요소 하나를 제외하고 모두 개방되었습니다.GC를 제외하고는 메모리 프로세서의 결과를 본다는 뜻이다.
개체 내의 순환 참조를 방지하기 위해 원래 의도대로 정확하게 쓰려면 WeakRef를 Parent 참조로 사용해야 합니다.
즉
const app = document.querySelector<HTMLDivElement>("#app")!;
class MyNode {
public children: MyNode[] = [];
constructor(public parent: WeakRef<MyNode> | null, public value: string) {}
}
function createCircularObject(
parent: WeakRef<MyNode> | null,
depth: number
): MyNode {
const n: MyNode = new MyNode(parent, Math.random().toString(32));
if (depth > 0) {
[...Array(30).keys()].map(() => {
const newNode = createCircularObject(new WeakRef(n), depth - 1);
n.children.push(newNode);
});
}
return n;
}
const button = document.createElement("button");
let cnt = 0;
button.textContent = "start";
button.addEventListener("click", () => {
const n = createCircularObject(null, 3);
console.log("round:", cnt++, n);
});
app.appendChild(button);
나무 구조의 교체로 아이만 살아남았고 부모가 없을 때 메모리가 새지 않았으면 하는 상황에서 참고가 정확하게 차단되었다.결과적으로 이것은 콘솔이다.로그를 멈추지 않으면 메모리가 유출됩니다.
결론
console.로그의 인쇄 디버깅은 참고 중 하나이기 때문에 WeakRef와 함께 사용할 때 참고 대상이 아니라 일부 id와 같은 간접값을 보아야 합니다.프린트 디버깅 후 운행 시간 행동이 달라진다는 얘기다.
Devotol을 켤 수 없는 상태의 constore일 수도 있습니다.로그의 메모리는 누설되지 않을 수 있지만 Devotool을 열지 않으면 Memory Profile을 시작할 수 없기 때문에 잘 모릅니다.
Reference
이 문제에 관하여(WeakRef 및 constorelog), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://zenn.dev/mizchi/articles/weakref-on-devtool텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)