다이시 카토가 만든 전역 상태 관리 라이브러리 중 하나인 Jotai에서는 WeakMap을 통해서 atom을 관리합니다. 이에 WeakMap이 무엇이고 왜 사용했는지에 대해 알아보려고 합니다.
우선 조타이 라이브러리의 공식 docs에서 언급한 왜 WeakMap을 사용했는지 입니다.
Let's start with an easy example. An atom is just a function that will return a configuration object. We are using WeakMap to map atom with their state.
WeakMap doesn't keep its keys in memory, so if an atom is garbage collected, its state will be garbage collected too. This helps avoid memory leaks.
요약하면 아래와 같습니다.
1. 조타이에서는 atom으로 상태관리를 하는데 atom은 함수이다.
2. WeakMap은 키를 메모리에 유지하지 않기 때문에 가비지 콜렉터가 atom을 수집하면 상태도 제거해준다.
즉, 손쉽게 메모리 누수를 방지하기 위해서 조타이에서는 WeakMap을 사용합니다. 그렇다면 왜 WeakMap은 무엇일까요?
WeakMap에 대해서
WeakMap은 이름부터 JS의 Map과 관계가 있어보입니다. 따라서 우선 Map에 대해서 알아보려고 합니다.
MDN문서에 설명하는 Map은 아래와 같습니다.
ECMAScript 6에서 값들을 매핑하기 위한 새로운 데이터 구조를 소개 하고 있다. 그중 하나인 Map객체는 간단한 키와 값을 서로 연결(매핑)시켜 저장하며 저장된 순서대로 각 요소들을 반복적으로 접근할 수 있도록 한다.
Object와 Map 비교
1. Object의 키는 Strings이며, Map의 키는 모든 값을 가질 수 있다.
2. Object는 크기를 수동으로 추적해야하지만, Map은 크기를 쉽게 얻을 수 있다.
3. Map은 삽입된 순서대로 반복된다.
4. 객체(Object)에는 prototype이 있어 Map에 기본 키들이 있다. (이것은 map = Object.create(null) 를 사용하여 우회할 수 있다. )
자바스크립트에서는 key,value가 쌍으로 이루어진 자료구조에는 Object, Map, WeakMap 3가지가 중요합니다.
앞서 말했듯이 조타이는 atom이라는 함수를 키로 상태를 관리합니다. 그리고 함수는 객체이기에, Map이나 WeakMap이 적합합니다.
그렇다면 WeakMap은 어떤 차이점이 있을까요?
Mdn에서 말하는 WeakMap의 장점은 아래와 같습니다.
- 가비지 컬렉션을 방지하지 않으므로 키 객체에 대한 참조가 결국 사라집니다.
- 키 객체가 WeakMap 밖의 다른 곳에서 참조되지 않으면 그 값의 가비지 컬렉션도 허용합니다.
그리고 자바스크립트 엔진의 가비지 컬렉터의 특징을 아래 예시를 통해 확인해보고자 합니다.
자바스크립트 엔진은 도달 가능한 (그리고 추후 사용될 가능성이 있는) 값을 메모리에 유지합니다.
출처 : https://ko.javascript.info/garbage-collection
let object = { name: 'Garbage' };
let collector = [object];
object = null; // 참조를 null로 덮어씀
console.log(JSON.stringify(collector[0])); // {"name":"Garbage"}
let obj2 = { name: 'Trash' };
let weakMap = new WeakMap();
weakMap.set(obj2, 'die');
obj2 = null; // 참조를 덮어씀
console.log(typeof weakMap.get(obj2)); //undefined
따라서 아래의 예시를 통해서 값을 확인해보면, 첫 번째 예시의 object의 경우 collector에 의해 참조되고 있기 때문에 도달할 수 있다고 평가되어 지고 값이 유지되어 있음을 볼 수 있습니다. 하지만 weakMap의 키로 사용된 obj2의 경우에는 참조로 덮어씌워 졌을 때, 가비지 컬렉터에 의해 수거됩니다. 그리고 WeakMap에서 키가 수거된 경우에는 자연스럽게 값도 같이 가비지 컬렉터에 의해 수거됐음을 확인할 수 있습니다.
Jotai에서 WeakMap
다이시 카토에 의하면 Jotai도 구독 모델 기반의 라이브러리입니다.
아래는 Jotai의 createStore입니다. WeakMap을 사용하는 것을 확인할 수 있네요.
export const createStore = (): Store => {
const atomStateMap = new WeakMap()
const getAtomState = <Value>(atom: Atom<Value>) => {
let atomState = atomStateMap.get(atom) as AtomState<Value> | undefined
if (!atomState) {
atomState = { d: new Map(), p: new Set(), n: 0 }
atomStateMap.set(atom, atomState)
}
return atomState
}
return buildStore(getAtomState)
}
이 소스코드에서 알 수 있듯이 WeakMap을 통해서 아톰의 상태를 저장하고, 이미 존재하는 값이라면 해동 값을 가져옵니다.
이를 통해서 만약 React에서 Jotai를 통해 상태관리를 할 경우에, 해당 컴퍼넌트가 unmount되어 더 이상 atom이 참조되고 있지 않다면, 가비지 컬렉터에 의해 atom이 수거되어 메모리 누수를 방지하는 장점을 얻습니다.
참고 문헌 및 출처
리액트 훅을 활용한 마이크로 상태 관리 - 다이시 카토 지음
https://ko.javascript.info/weakmap-weakset
위크맵과 위크셋
ko.javascript.info
https://ko.javascript.info/garbage-collection
가비지 컬렉션
ko.javascript.info
https://developer.mozilla.org/ko/docs/Web/JavaScript/Guide/Keyed_collections
키 기반 컬렉션 - JavaScript | MDN
이번 장에서는 입력된 키값을 기준으로 정렬되는 데이터의 집합(자료 구조)에 대해 소개 할 것이다. Map과 Set은 입력된 순서대로 반복적으로 접근 가능한 요소들을 포함하고 있다.
developer.mozilla.org
'프론트엔드' 카테고리의 다른 글
React 유저가 느낀 Vue (0) | 2025.01.13 |
---|---|
Three.js 튜토리얼 - 기본 구조와 사용 방법 (0) | 2024.04.10 |
(React)컴파운드 패턴으로 드롭다운 컴퍼넌트 만들기-1 구현하기 (0) | 2024.03.28 |
React에 StoryBook 도입하기(tailwind) (0) | 2024.02.23 |
DOM과 Virtual DOM (0) | 2024.02.22 |