๋ค์ด๊ฐ๋ฉด์
์ด ๊ธ์ 1ํธ '๊ธฐ๋ณธํ ๋ฐ์ดํฐ์ ์ฐธ์กฐํ ๋ฐ์ดํฐ๋ฅผ ์์์ผ ํ๋ ์ด์ '์ ๋ํ ํ์ํธ์ ๋๋ค.
Java๋ C, C++ ์ธ์ด์์๋ ๊ธฐ๋ณธํ์ ์คํ์, ์ฐธ์กฐํ์ ํ์ ๋ค์ด๊ฐ๋ค๊ณ ์๊ณ ์๊ณ , JS ๋ํ ๊ธฐ๋ณธํ์ ์คํ, ์ฐธ์กฐํ์ ํ์ ํ ๋น๋๋ค๊ณ ์ฃผ์ฅํ๋ ๊ธ๋ค์ด ๋ง์ต๋๋ค. ๊ทธ๋ ๊ฒ ์๊ณ ์์์ต๋๋ค.
ํ์ง๋ง JS๋ ๋ค๋ฆ ๋๋ค. ๊ธฐ๋ณธํ, ์ฐธ์กฐํ ๋ชจ๋ ํ์ ํ ๋น๋๋๋ฐ, ์ ์ฌํ ๋์ '์ฝ์ด ์๋ฐ์คํฌ๋ฆฝํธ' ์ฑ ์์๋ "์๋ฐํ ๋ฐ์ง๋ฉด ์๋ฐ์คํฌ๋ฆฝํธ์ ๋ชจ๋ ๋ฐ์ดํฐ ํ์ ์ ์ฐธ์กฐํ ๋ฐ์ดํฐ์ผ ์๋ฐ์ ์๋ค."๋ผ๋ ๋ถ๋ถ์ด ์ธ๊ธ๋ฉ๋๋ค.
๊ทธ๋์ ์ด๋ฒ ํฌ์คํ ์์๋ JavaScript์์ ๊ธฐ๋ณธ ๊ฐ์ด ์คํ์ ํ ๋น๋๊ณ ๊ฐ์ฒด๋ ํ์ ํ ๋น๋๋ค๊ณ ํ๋ ์ฃผ์ฅ์ด ์ฌ์ค์ด ์๋๋ฉฐ, ์ด์ ๋ํด ๋ฆฌ์์นํ ๊ฒ๋ค์ ์ ๋ฆฌํด ๋ณด์์ต๋๋ค.
์ด ๊ธ์ ์๋น์๋ ๊ฑฐ์ https://www.zhenghao.io/posts/javascript-memory ์ https://www.youtube.com/watch?v=OG_AZnPokGw&t=510s์ ์ฐธ๊ณ ํ์์ต๋๋ค.
์คํ ๋ฉ๋ชจ๋ฆฌ์ ํ ๋ฉ๋ชจ๋ฆฌ๋ฅผ ์ง์ ํ์ธํด๋ณด์
- ์คํ ๋ฉ๋ชจ๋ฆฌ ํ์ธ
- v8์ ์คํ ํฌ๊ธฐ๋ฅผ ๊ฐ์ ธ์ต๋๋ค. 864kb๋ฅผ ํ ๋น ๋ฐ์์ต๋๋ค.
- ์๋์ ๊ฐ์ ์ฝ๋๋ฅผ ์คํํฉ๋๋ค.
function memoryUsed() {
const mbUsed = process.memoryUsage().heapUsed / 1024 / 1024
console.log(`Memory used: ${mbUsed} MB`);
}
console.log('before');
memoryUsed()
const bigString = 'x'.repeat(10*1024*1024)
console.log(bigString); // need to use the string otherwise the compiler would just optimize it into nothingness
console.log('after');
memoryUsed()
- bitString ์ฐ์ฐ ์
- bigString ์ฐ์ฐ ํ
๋ฌธ์์ด ์ฐ์ฐ์ ํตํด 10MB์ ๋ฉ๋ชจ๋ฆฌ๊ฐ ์ฌ์ฉ๋์๋๋ฐ, ์ด๋ ์คํ์ด ์๋ ํ์์ ํ ๋น๋ ๊ฒ์ ๋๋ค. ์ ์ด๋ฏธ์ง๋ฅผ ํตํด ํ ์ฌ์ฉ๋์ด ์ ํํ 10MB๋งํผ ์ฆ๊ฐํ ๊ฒ์ ํ์ธํ ์ ์์ต๋๋ค(3MB->13MB). ์ด๋ฅผ ํตํด ๊ธฐ๋ณธํ ๋ฐ์ดํฐ์ธ string์ด ํ์์ ๋ฉ๋ชจ๋ฆฌ๊ฐ ํ ๋น๋์์์ ์ ์ ์์ต๋๋ค.
bigString
์ ๋ค๋ฅธ ๋ณ์์ ํ ๋นํ๋ฉด ํ ๋ฉ๋ชจ๋ฆฌ๋ก ๋ถํฐ ์ด 20mb ๋ฅผ ํ ๋น ๋ฐ๊ฒ ๋๋ ๊ฑธ๊น?
const copyBigString = bigString
๊ฐ์ ๋ฐ์ดํฐ๋ฅผ ์ฐธ์กฐํ๋ ๋ณ์๊ฐ ์์ ๊ฒฝ์ฐ ์ด๋ป๊ฒ ๋๋์ง devtools๋ฅผ ํตํด ํ์ธํด ๋ด ๋๋ค.
const btn = document.querySelector('#btn');
btn.addEventListener('click', (e) => {
const string1 = 'foo'
const string2 = 'foo'
})
๋ฒํผ์ ํด๋ฆญํ์ ๋ foo
๋ผ๋ ๋ฌธ์์ด์ ๋ด์ ๋ณ์๊ฐ 2๊ฐ ์์ผ๋ (string1, string2) ๋ฉ๋ชจ๋ฆฌ๋ฅผ ํ ๋นํ๋ ๊ณณ์ด ๋ ๊ฐ์ด์ง ์์๊น ํ์ง๋ง ๊ฐ์ ๋ฌธ์์ด ๋ฐ์ดํฐ๋ฅผ ์ฌ๋ฌ ๋ฒ ๋ฉ๋ชจ๋ฆฌ์ ์ ์ฅํ๋ ๋์ ๋จ์ผ ๋ณต์ฌ๋ณธ์ ์์ฑํ๊ณ ์ฌ๋ฌ ์ฐธ์กฐ๊ฐ ๊ฐ์ ๋ฐ์ดํฐ๋ฅผ ๊ฐ๋ฆฌํค๋๋ก ํ๋ ๋ฐฉ์์ผ๋ก ์๋ํฉ๋๋ค. ์ด๋ฅผ ๋ฌธ์์ด ์ธํด์ด๋ผ๊ณ ํ๊ณ v8์์๋ ์ด ๊ธฐ์ ์ ์ฌ์ฉํ์ฌ ๋ฉ๋ชจ๋ฆฌ๋ฅผ ์ต์ ํํฉ๋๋ค.
์๋์ 'foo' @1169645๋ก ํ ๊ฐ์ ๋ฐ์ดํฐ๋ง ์ ์ฅ๋ ๊ฒ์ผ๋ก ํ์ธํ ์ ์์ต๋๋ค.
๊ทธ๋ผ 'foo' @116945๋ ๋ฌธ์์ด์ด ๋ด๊ธด ์ฃผ์์ผ๊น?
์๋๋๋ค. ๊ธ์ด์ด์ ๋ด์ฉ์ ์ธ์ฉํ์๋ฉด ๋ค์๊ณผ ๊ฐ์ต๋๋ค.
Chrome DevTools does not show where the pointers reside in memory but rather where they point to. Also the numbers you see e.g. @206637 do not represent raw memory addresses. If you want to inspect the actual memory, you need to use a native debugger.
@116945๊ฐ ์ค์ ๋ฐ์ดํฐ๋ฅผ ๋ด๊ณ ์๋ ๋ฉ๋ชจ๋ฆฌ ์ฃผ์๊ฐ ์๋๋ผ๋ ์ ์ด๊ณ , ๋ฐ์ดํฐ๋ฅผ ๋ด๊ณ ์๋ ๋ฉ๋ชจ๋ฆฌ ์ฃผ์๋ฅผ ๋ฐ๋ผ๋ณด๊ณ ์๋ ํฌ์ธํฐ ์ด๋ค. ๋ผ๊ณ ์ดํด๋ฉ๋๋ค.
์ฌ๊ธฐ์ ๊ธ์ด์ด๊ฐ ํํํ ์๋ฐ์คํฌ๋ฆฝํธ์ ๋ณ์๋ ๋๋ถ๋ถ ํฌ์ธํฐ
JavaScript variables are (mostly) pointers
๋ผ๊ณ ํํ ํ๋๋ฐ ๊ทธ๋ ๊ทธ๋ด๊ฒ์ด ํฌ๋กฌ์์ ์ฌ์ฉํ๋ JS์์ง์ธ v8์ด c++ ๋ก ์ฐ์ฌ์ก์ผ๋ฏ๋ก ํฌ์ธํฐ ๊ฐ๋ ์ ์ฐจ์ฉํ์ง ์์์๊น ๋ผ๋ ์๊ฐ๋ ๋ญ๋๋ค.
์ด๋ v8 ์ ์ฝ๋๋ฅผ ํตํด ์ด๋ ์ ๋๋ ์ ์ถ ํ ์ ์๋๋ฐ,
V8_INLINE Local<Primitive> Undefined(Isolate* isolate) {
using S = internal::Address;
using I = internal::Internals;
I::CheckInitialized(isolate);
S* slot = I::GetRoot(isolate, I::kUndefinedValueRootIndex); //โ
return Local<Primitive>(reinterpret_cast<Primitive*>(slot));
}
S(์ฆ, internal::Address*) ํ์
์ slot
ํฌ์ธํฐ๋ฅผ ๋ฐํํ๊ณ ์์ต๋๋ค.
undefined์ ์์ ๊ฐ์กฐ์ฐจ๋ ๋ด๋ถ์ ์ผ๋ก๋ C++ ๊ฐ์ฒด๋ฅผ ๊ฐ๋ฆฌํค๋ ๋ฉ๋ชจ๋ฆฌ ์ฃผ์๋ก ๊ตฌํ๋์์ต๋๋ค.
๊ทธ๋ผ ๊ณ ์์ค์ธ ์๋ฐ์คํฌ๋ฆฝํธ์์๋ ๋ณ์์ ๊ฐ์ ํ ๋นํ์ ๋ ๋๋ ์๋ฌด๊ฒ๋ ํ ๋นํ์ง ์์ ๊ฒฝ์ฐ(undefined)์ผ ๋, ๋ณ์๋ ๋ฐ์ดํฐ์ ์ค์ ๊ฐ์ด ์๋, ๋ฐ์ดํฐ๊ฐ ์ ์ฅ๋ ์์น(๋ฉ๋ชจ๋ฆฌ ์ฃผ์)๋ฅผ ์ฐธ์กฐํ๋ค๋ ์ ์ผ๋ก ์ดํดํ ์ ์์ต๋๋ค.(์ด ๋ถ๋ถ์ ์ ๊ฐ ์ดํดํ ๋ฐ๋ฅผ ํํํ ๊ฒ์ธ๋ฐ, ์๋ชป ์ ๊ทผ, ํํํ๋ค๋ฉด ์๋ ค์ฃผ์ธ์.)
๊ทธ๋ ๋ค๋ฉด ์ ๋ง ๋ชจ๋ Primitive ๋ฐ์ดํฐ ํ์ ์ ์ฐธ์กฐํ์ธ๊ฐ?
๊ทธ๋ ์ง๋ ์๋ค ์ ๋๋ค. small integer -231์์ 231-1๊น์ง์ ์ ์๋ 231์์ ์ต์ ํ๋์ด ์ถ๊ฐ ์ ์ฅ์๋ฅผ ํ ๋นํ ํ์๊ฐ ์๋ค๊ณ ํฉ๋๋ค. ์ด์ ๋ํ ๋ ์์ธํ ์ค๋ช ์ ์๋ ๋งํฌ๋ฅผ ์ฐธ๊ณ ํด ์ฃผ์ธ์.
๋ง๋ฌด๋ฆฌ
์๋ฃ๋ค์ ํตํด ์ฑ ์์ ๋ณด๋ "์๋ฐํ ๋ฐ์ง๋ฉด ์๋ฐ์คํฌ๋ฆฝํธ์ ๋ชจ๋ ๋ฐ์ดํฐ ํ์ ์ ์ฐธ์กฐํ ๋ฐ์ดํฐ์ผ ์ ๋ฐ์ ์๋ค." ์ ๋ํ ๊ถ๊ธ์ฆ์ด ์ด๋์ ๋ ํด์๋ ๊ฒ ๊ฐ์ต๋๋ค.
์ฐธ์กฐํ, ๊ธฐ๋ณธํ ๋ชจ๋ ํ์์ ํ ๋น ๋๋ค๋ ๊ฒ์ ๋ฌธ์์ด ํ ๋น ์์์ธ ๋ ธ๋์
process.memoryUsage()
๋ฅผ ํตํด ํ์ธํ์ผ๋ฉฐ, chrome devtool์ heap allocation์์๋ string ํ์ ์ด ํ์์ ํ ๋น๋๋ ์ ๋ ์ ์ ์์์ต๋๋ค.์๋ฐ์คํฌ๋ฆฝํธ์ ๊ธฐ๋ณธํ๋ ๊ฒฐ๊ตญ ์ฐธ์กฐํ ์ด๋ค (small integer๋ฅผ ์ ์ธํ๊ณ ). ๋ณ์์ ํ ๋นํ๊ธฐ ์ํด์๋ ๋๊ฐ์ ๋ณต์ฌํ๋๊ฒ์ด ์๋ ์ฃผ์๊ฐ์ ๋ณต์ฌํ๋ ์ ์ v8์ฝ๋๋ฅผ ํตํด ๊ทธ๋ฆฌ๊ณ ๊ธฐ๋ณธ๊ฐ์ธ undefined๋ ํฌ์ธํฐ๋ฅผ ๋ฆฌํดํ๋ ๋ถ๋ถ์ผ๋ก ํ์ธํ ์ ์์์ต๋๋ค.
์ฐธ๊ณ ์๋ฃ
- JavaScript Memory Model Demystified, 22 JANUARY, 2022, https://www.zhenghao.io/posts/javascript-memory#javascript-variables-are-mostly-pointers
- Kateryna Porshnieva. Visualised guide to memory management in JavaScript | JSHeroes 2023, JSHeroes 2023 https://www.youtube.com/watch?v=OG_AZnPokGw&t=510s