前言
大家好,我是林三心, 用最通俗易懂的話講最難的知識點 是我的座右銘, 基礎是進階的前提 是我的初心。
在我們的認知裏:基礎型別存棧記憶體,參照數據型別存堆記憶體。
const a = '林三心'
const b = {
age: 18,
height: 180
}
超長字串
大家都知道,
字串
屬於
基礎型別
,所以大家會覺得
字串
是存在
棧記憶體
中的,但是大家要知道,V8預設棧記憶體是
984Kib
,那如果一個
超長字串 > 984Kib
能裝的進
棧記憶體
嗎?這也就是一個比較經典的問題——
大象裝箱問題
,試問:一頭大象能裝進一個小箱子裏嗎?
一探究竟
堆快照
先來看一段程式碼
const func = function() {
this.str1 = '林三心'
this.str2 = 'Sunshine_Lin'
}
const a = new func()
const b = new func()
然後咱們來看看
堆快照
的詳情
上面的結果可以看出:
a 和 b的
str1
都指向同一個地址
a 和 b的
str2
都指向同一個地址
那我們可不可以猜測出一個結論: 字串的內容存於堆記憶體中,指標存於棧記憶體中,且相同的字串指向同一個堆記憶體地址
修改和新增字串
我們稍微修改下程式碼
const func = function() {
this.str1 = '林三心'
this.str2 = 'Sunshine_Lin'
}
const a = new func()
const b = new func()
// 修改str1
a.str1 = '哈哈哈哈哈哈哈哈哈哈'
// 新增str3,跟str2一樣
a.str3 = 'Sunshine_Lin'
再來看看現階段的
堆快照
的詳情
上面的結果可以看出:
str1
修改成一個新的字串後,重新開辟了一個記憶體空間(新地址)
str3
新增之後,指標指向已有的
Sunshine_Lin
的記憶體空間
那我們可不可以猜測出一個結論: 新增或者修改字串後,如果是一個之前不存在的字串,則新開辟記憶體空間,如果是已有的,則直接使用已有的記憶體空間
源分碼析
當我們聲明一個字串時:
1、v8內部有一個名為
stringTable
的
hashmap
緩存了所有字串,在V8閱讀我們的程式碼,轉換抽象語法樹時,每遇到一個字串,會根據其特征換算為一個
hash值
,插入到
hashmap
中。在之後如果遇到了
hash值
一致的字串,會優先從裏面取出來進行比對,一致的話就不會生成新字串類。
2、緩存字串時,根據字串不同采取不同
hash
方式。
源碼
通俗易懂總結
字串的數據存於 堆記憶體 中,棧記憶體 中只是存其 地址指標
當我們新建一個字串時,V8會從記憶體中尋找一下是否已經有存在的一樣的字串,找到的話直接復用。如果找不到的話,則開辟一塊新的記憶體空間來存這個字串,並把地址賦給變量。
大家有沒有想過,為什麽字串不能透過下標索引來進行修改呢?因為字串的修改本質上只能是透過整個的修改,而不能局部修改。
結語
喜歡林三心的朋友,可以關註公眾號【前端之神】,進入【千人學習大群】哦,或者可以給三心點個贊,點個在看哦,謝謝你