最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

深入內(nèi)存原理談JS中變量存儲在堆中還是棧中

 更新時間:2021年09月22日 09:58:48   作者:六耳  
JavaScript中基本類型存儲在堆中還是棧中,百度一下有很多不同的答案,本篇文章就來給大家為此做個詳細(xì)的介紹,需要的朋友可以參考一下

JavaScript中基本類型存儲在堆中還是棧中?

---- 不基本類型的基本類型

看到這個問題,相信大家都覺得這個題目實在基礎(chǔ)的不能再基礎(chǔ)了。隨手百度一下,就能看到很多人說:基本類型存在棧中,引用類型存在堆中。

真的這么簡單么?

一、裝不進(jìn)冰箱的大象

讓我們看一下這段代碼:

在這里,我們聲明了一個67MiB大小的字符串,如果字符串真的存在棧中,這就不好解釋了。畢竟,v8默認(rèn)的棧區(qū)大小為984KiB??隙ㄊ谴娌幌碌?。

注:在不同時期,不同操作系統(tǒng)中V8對于字符串大小的限制并不相同。大概有個范圍是256MiB ~ 1GiB

node --v8-options | grep -B0 -A1 stack-size


說到這里,各位是不是心里已經(jīng)開始疑惑了呢。難道百度的答案不對,得用谷歌搜?

讓我們看看這到底是怎么回事。

二、影分身的字符串

const BasicVarGen = function () {
    this.s1 = 'IAmString'
    this.s2 = 'IAmString'
}


let a = new BasicVarGen()
let b = new BasicVarGen()

在這里,我們聲明了兩個一樣的對象,每個對象包括兩個相同的字符串。

通過開發(fā)者工具,我們看到雖然我們聲明了四個字符串,但是其內(nèi)存指向了同一個地址。

備注:chrome無法查看實際地址,此處為抽象后的地址

這說明了啥?說明了四個字符串中存的是引用地址。

所以上文中那個無法裝進(jìn)冰箱的大象,也就好解釋了。字符串并沒有存到棧中,而是存到了一個別的地方,再把這個地方的地址存到了棧中。

那,讓我們修改一下其中一個字符串的內(nèi)容

const BasicVarGen = function () {
    this.s0 = 'IAmString'
    this.s1 = 'IAmString'
}


let a = new BasicVarGen()
let b = new BasicVarGen()
debugger
a.s0 = 'different string'
a.s2 = 'IAmString'

debugger之前的內(nèi)存快照

debugger之后的內(nèi)存快照

我們可以看到,a.s0 一開始內(nèi)容為 ‘IAmString' ,在我們修改其內(nèi)容后,地址發(fā)生了變化。

而我們新增的a.s2 其內(nèi)容為 ‘IAmString' ,其地址與其他值為 ‘IAmString'  的變量保持一致。

當(dāng)我們聲明一個字符串時:

  1. v8內(nèi)部有一個名為stringTablehashmap緩存了所有字符串,在V8閱讀我們的代碼,轉(zhuǎn)換抽象語法樹時,每遇到一個字符串,會根據(jù)其特征換算為一個hash值,插入到hashmap中。在之后如果遇到了hash值一致的字符串,會優(yōu)先從里面取出來進(jìn)行比對,一致的話就不會生成新字符串類。
  2. 緩存字符串時,根據(jù)字符串不同采取不同hash方式。

所以讓我們梳理一下,在我們創(chuàng)建字符串的時候,V8會先從內(nèi)存中(哈希表)查找是否有已經(jīng)創(chuàng)建的完全一致的字符串,如果存在,直接復(fù)用。如果不存在,則開辟一塊新的內(nèi)存空間存進(jìn)這個字符串,然后把地址賦到變量中。這也是為什么我們不能直接用下標(biāo)的方式修改字符串: V8中的字符串都是不可變的。

拿出一個js的基本類型拷貝舉例講一下v8的實現(xiàn)邏輯和常規(guī)的大家理解的邏輯(雅文)

 例:

var a = "劉瀟灑";   // V8讀取字符串后,去stringTable查找是否存在 不存在 hashTable 插入 '劉瀟灑' 并把'劉瀟灑'的引用存入 a
var b = a; // 直接拷貝 '劉瀟灑' 的引用 
b = "譚雅文"; // 查找 無 存入stringTable


疑問點:

const BasicVarGen = function () {
    this.s0 = 'IAmString'
    this.s1 = 'IAmString'
}


let a = new BasicVarGen()
let b = new BasicVarGen()
debugger
a.s0 = 'different string'
a.s2 = 'IAmString'


a.s3 = a.s2+a.s0;   // 疑問點: 字符串拼接做了哪些操作?
a.s4 = a.s2+a.s

同時申請兩個拼接的字符串,內(nèi)容相同。

可以看到,雖然其內(nèi)容相同。但是地址并不相同。而且,地址前方的Map描述也發(fā)生了變化。

字符串拼接時如果以傳統(tǒng)方式(如 SeqString)存儲,拼接操作的時間復(fù)雜度為 O(n) ,采用 繩索結(jié)構(gòu)[Rope Structure] (也就是 ConsString 所采用的數(shù)據(jù)結(jié)構(gòu))可以減少拼接所花費的時間。

如果字符串是這樣,那別的基本類型也是如此么?

三、如朕親臨的 ‘奇球'

說完字符串,讓我們看看V8中另外一類典型的‘基本類型':oddBall。

拓展自oddBalltype

讓我們再做一個小實驗:

 

我們可以看到 上圖中列舉的基本類型,地址也是相同的。在賦值時,也是就地復(fù)用。(而且這些拓展自oddBall的基本類型,其地址是固定的,也就是說,在V8跑起來的第一時間,不管我們有沒有聲明這些基本類型,他們都已經(jīng)被創(chuàng)建完畢了。而我們聲明對象時,賦的是他們的引用。這也可以解釋為什么我們說基本類型是賦到棧中:在V8中,存放在 @73 的值,永遠(yuǎn)是空字符串,那么v8就可以等效把這些地址視為值本身。)

讓我們看看源碼,驗證一下:

生成各種oddBall類型的方法,可以看出返回的是一個地址

undefined賦值給一個變量,其實賦的是地址

getRoot方法

偏移量定義的地方

四、撲朔迷離的數(shù)字

之所以叫撲朔迷離的數(shù)字,是因為還沒有搞明白其分配與改變時內(nèi)存分配的機(jī)制。(其內(nèi)存是動態(tài)的)

數(shù)字在V8中分為 smiheapNumber。

smi 直接存進(jìn)內(nèi)存范圍為 :-2³¹ 到 2³¹-1(2³¹≈2*10⁹)的整數(shù)

heapNumber 類似字符串 不可變范圍為 :所有非smi的數(shù)字

最低位用來表示是否為指針 最低位為1 則是一個指針

const o = {
  x: 42,  // Smi
  y: 4.2, // HeapNumber
};


o.x 中的 42 會被當(dāng)成 Smi 直接存儲在對象本身,而 o.y 中的 4.2 需要額外開辟一個內(nèi)存實體存放,并將 o.y 的對象指針指向該內(nèi)存實體。

如果是 32 位操作系統(tǒng),用32位表示smi 可以理解,可是64位操作系統(tǒng)中,為什么 smi 范圍也是 -2³¹ 到 2³¹-1(2³¹≈2*10⁹)?

ECMAScript 標(biāo)準(zhǔn)約定 number 數(shù)字需要被當(dāng)成 64 位雙精度浮點數(shù)處理,但事實上,一直使用 64 位去存儲任何數(shù)字實際是非常低效的(空間低效,計算時間低效 smi大量使用位運(yùn)算),所以 JavaScript 引擎并不總會使用 64 位去存儲數(shù)字,引擎在內(nèi)部可以采用其他內(nèi)存表示方式(如 32 位),只要保證數(shù)字外部所有能被監(jiān)測到的特性對齊 64 位的表現(xiàn)就行。

const cycleLimit = 50000
console.time('heapNumber')
const foo = { x: 1.1 };
for (let i = 0; i < cycleLimit; ++i) {
// 創(chuàng)建了多出來的heapNumber實例
  foo.x += 1; 
}
console.timeEnd('heapNumber') // slow   


console.time('smi')
const bar = { x: 1.0 };
for (let i = 0; i < cycleLimit; ++i) {
  bar.x += 1;
}
console.timeEnd('smi')  // fast

疑問點:

const BasicVarGen = function () {


    this.smi1 = 1
    this.smi2 = 2
    this.heapNumber1 = 1.1
    this.heapNumber2 = 2.1
}
    let foo = new BasicVarGen()
    let bar = new BasicVarGen()
    
    debugger
    
    baz.obj1.heapNumber1 ++

在數(shù)字中,一個數(shù)字的值都沒有修改,其他的數(shù)字地址也都變了。

五、小結(jié):基本類型到底存在哪里?

字符串:   存在堆里,棧中為引用地址,如果存在相同字符串,則引用地址相同。

數(shù)字:        小整數(shù)存在棧中,其他類型存在堆中。

其他類型:引擎初始化時分配唯一地址,棧中的變量存的是唯一的引用。

這里只能算是大概講明白了基本類型存在哪里,

到此這篇關(guān)于深入內(nèi)存原理談JS中變量存儲在堆中還是棧中的文章就介紹到這了,更多相關(guān)JS中變量存儲在堆中還是棧中內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • 微信小程序 HTTPS報錯整理常見問題及解決方案

    微信小程序 HTTPS報錯整理常見問題及解決方案

    這篇文章主要介紹了微信小程序 HTTPS報錯常見問題及解決方案的相關(guān)資料,需要的朋友可以參考下
    2016-12-12
  • 采用CSS和JS,剛好我最近有個站點要用到下拉菜單!

    采用CSS和JS,剛好我最近有個站點要用到下拉菜單!

    采用CSS和JS,剛好我最近有個站點要用到下拉菜單!...
    2006-06-06
  • 微信小程序 實現(xiàn)拖拽事件監(jiān)聽實例詳解

    微信小程序 實現(xiàn)拖拽事件監(jiān)聽實例詳解

    這篇文章主要介紹了微信小程序 實現(xiàn)拖拽事件監(jiān)聽實例詳解的相關(guān)資料,在開發(fā)不少應(yīng)用或者軟件都要用到這樣的方法,這里就對微信小程序?qū)崿F(xiàn)該功能進(jìn)行介紹,需要的朋友可以參考下
    2016-11-11
  • JavaScript中document.activeELement焦點元素介紹

    JavaScript中document.activeELement焦點元素介紹

    這篇文章主要給大家分享 JavaScript中document.activeELement焦點元素介紹,下面文章圍繞了document.activeElement屬性展開詳細(xì)內(nèi)容,需要的朋友可以參考一下,希望對大家有所幫助
    2021-11-11
  • 15個值得收藏的JavaScript函數(shù)

    15個值得收藏的JavaScript函數(shù)

    在開發(fā)一個JavaScript項目時,經(jīng)常會用到以前開發(fā)過的一些工具函數(shù),收集這些函數(shù),當(dāng)你需要它們的時候,將節(jié)省你大量的開發(fā)時間,本文將給大家?guī)?5個常用的工具函數(shù),需要的小伙伴可以參考下
    2021-09-09
  • 微信小程序 Page()函數(shù)詳解

    微信小程序 Page()函數(shù)詳解

    這篇文章主要介紹了微信小程序 Page()函數(shù)詳解的相關(guān)資料,在開發(fā)過程中肯定會遇到Page()函數(shù),希望能幫助到大家,需要的朋友可以參考下
    2016-10-10
  • JavaScript parseInt0.0000005打印5原理解析

    JavaScript parseInt0.0000005打印5原理解析

    這篇文章主要為大家介紹了JavaScript parseInt0.0000005打印5原理解析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2022-07-07
  • 微信小程序 視圖容器組件的詳解及實例代碼

    微信小程序 視圖容器組件的詳解及實例代碼

    這篇文章主要介紹了微信小程序 視圖容器組件的詳解及實例代碼的相關(guān)資料,這里對基礎(chǔ)知識進(jìn)行了詳細(xì)介紹并附有簡單實例代碼,需要的朋友可以參考下
    2017-01-01
  • 微信小程序 動畫的簡單實例

    微信小程序 動畫的簡單實例

    這篇文章主要介紹了微信小程序 動畫的簡單實例的相關(guān)資料,希望通過本文能幫助到大家,需要的朋友可以參考下
    2017-10-10
  • js實現(xiàn)兔年轉(zhuǎn)圈圈動畫示例

    js實現(xiàn)兔年轉(zhuǎn)圈圈動畫示例

    這篇文章主要為大家介紹了js實現(xiàn)兔年轉(zhuǎn)圈圈動畫示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-01-01

最新評論

黔江区| 开阳县| 长兴县| 望都县| 徐闻县| 冀州市| 化隆| 伊春市| 江安县| 右玉县| 北碚区| 柳江县| 莫力| 饶阳县| 武定县| 连州市| 永胜县| 青海省| 商水县| 濮阳县| 安乡县| 揭东县| 慈溪市| 益阳市| 白河县| 交城县| 蕲春县| 石首市| 锦州市| 伊金霍洛旗| 且末县| 上饶市| 上思县| 秀山| 虹口区| 宁陵县| 高碑店市| 黔东| 汤原县| 咸宁市| 安庆市|