欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

一文詳解Javascript內(nèi)存機制與垃圾回收

 更新時間:2023年06月15日 10:32:49   作者:越谷  
這篇文章主要給大家詳細介紹了Javascript的內(nèi)存機制與垃圾回收,文中又詳細的代碼示例,對我們學(xué)習(xí)Javascript有一定的幫助,需要的同學(xué)可以借鑒閱讀

一 內(nèi)存機制

1.1 數(shù)據(jù)類型

Javascript 是一種動態(tài)的(在運行過程中檢查數(shù)據(jù)類型,)、弱類型(同一個變量可以保存不同類型的數(shù)據(jù))的語言。

Javascript 數(shù)據(jù)類型一共有 8 種: Boolean,Null,Undefined,Number,BigInt,String,Symbol,Object。前 7 種數(shù)據(jù)類型為原始類型,Object引用類型。兩種類型的數(shù)據(jù)在內(nèi)存中存放的位置不同。

1.2 內(nèi)存空間

Javascript 在執(zhí)行的過程中,主要有三種類型的內(nèi)存空間,分別是:代碼空間、??臻g、堆空間。

代碼空間主要是存儲可執(zhí)行代碼的。

原始數(shù)據(jù)類型存儲在??臻g中, 引用數(shù)據(jù)類型存儲在堆空間中。

說明示例:

function foo(){
    var a = "極客時間"
    var b = a
    var c = {name:"極客時間"}
    var d = c
}
foo()

??臻g,也就是之前提起的調(diào)用棧,用來存儲執(zhí)行上下文。

上述代碼執(zhí)行到第 3 行的時候,變量 a 和 b 的值都直接保存在執(zhí)行上下文中,執(zhí)行上下文又被壓入棧空間中,所以可以理解為變量 a 和 b 都存放在棧空間中。

當(dāng)執(zhí)行到第 4 行,Javascript 引擎判斷變量 c 的值是引用類型,Javascript 引擎將該值分配到堆空間里,分配后該值會有一個在堆空間的地址,然后將該地址賦值給變量 c。第 5 行,將 c 賦值給 d,實際是將引用地址賦值給了 d,修改引用類型對象的值,改的是堆空間中數(shù)據(jù)的值。

??臻g因為要維護執(zhí)行上下文,影響程序的執(zhí)行效率,所以空間一般比較小,可以用來存放原始類型的小數(shù)據(jù);引用類型的數(shù)據(jù)可以很大,所以堆空間比較大,不過堆空間分配內(nèi)存和回收內(nèi)存會占用一定的時間。

??臻g切換執(zhí)行上下文狀態(tài):

1.3 閉包內(nèi)的數(shù)據(jù)存儲

閉包內(nèi)的變量存儲到??臻g還是堆空間?

說明示例:

function foo() {
    var myName = "極客時間"
    let test1 = 1
    const test2 = 2
    var innerBar = { 
        setName:function(newName){
            myName = newName
        },
        getName:function(){
            console.log(test1)
            return myName
        }
    }
    return innerBar
}
var bar = foo()
bar.setName("極客邦")
bar.getName()
console.log(bar.getName())

執(zhí)行上述代碼,當(dāng) foo 函數(shù)執(zhí)行完之后,調(diào)用棧中的 foo 函數(shù)的執(zhí)行上下文會被銷毀,由于變量 myName 和 test1 持續(xù)存在外部引用,Javascript 引擎判斷這是一個閉包,會在堆空間中創(chuàng)建一個closure(foo)的對象,這個對象中包含這兩個被引用的變量。

二 垃圾回收

一些數(shù)據(jù)在使用后就不再需要了,這部分數(shù)據(jù)繼續(xù)存在內(nèi)存里,并且逐漸積累,會占用越來越多的空間,通過垃圾回收機制以釋放有限的內(nèi)存空間。

2.1 不同語言的垃圾回收策略

一般,垃圾回收分為手動回收自動回收兩種策略。

以 C / C++ 為例,使用的是手動回收策略,內(nèi)存的分配與銷毀都是由程序員寫的代碼控制的,如果不主動銷毀垃圾數(shù)據(jù),將導(dǎo)致內(nèi)存泄漏。

以 Javascript / Java 為例,垃圾數(shù)據(jù)由內(nèi)置的垃圾回收器自動回收,不需要通過編寫代碼手動釋放。

2.2 調(diào)用棧的垃圾回收機制

Javascript 引擎把執(zhí)行上下文壓入調(diào)用棧的同時,使用一個記錄當(dāng)前執(zhí)行狀態(tài)的指針(ESP)指向當(dāng)前的執(zhí)行上下文,表示正在執(zhí)行該執(zhí)行上下文。

當(dāng)該執(zhí)行上下文運行完畢,ESP 下移,這個下移的操作就是銷毀被執(zhí)行過的上下文的過程。

示例說明:

function foo(){
    var a = 1
    var b = {name:"極客邦"}
    function showName(){
      var c = 2
      var d = {name:"極客時間"}
    }
    showName()
}
foo()

2.3 堆空間垃圾回收機制

2.3.1 代際假說

代際假說觀點認為,大部分對象在內(nèi)存中有用的時間很短,一經(jīng)分配內(nèi)存,很快就變得不可訪問;少量數(shù)據(jù)持續(xù)活躍,活的很久。

2.3.2 V8 垃圾回收機制:分代收集

基于代際假說,V8 把堆分為老生代新生代,新生代中存放的是生存時間短的對象(1—8M空間),老生代中存放的是生存時間久的對象(空間比較大)。

針對新生代和老生代,V8 使用不用的回收機制,以便更高效的進行垃圾回收。使用主垃圾回收器回收老生代的垃圾數(shù)據(jù),使用副垃圾回收器回收新生代的垃圾數(shù)據(jù)。

垃圾回收原理

  • 標記空間中的活動對象(還在使用的對象)和非活動對象(可以回收的對象)。
  • 標記完成之后,統(tǒng)一清理內(nèi)存中所有被標記的可回收對象,回收這部分對象占據(jù)的內(nèi)存。
  • 內(nèi)存整理:頻繁回收對象之后,內(nèi)存中存在大量不連續(xù)空間(內(nèi)存碎片),如果要分配較大連續(xù)內(nèi)存時,可能出現(xiàn)內(nèi)存不足的情況,所以需要將內(nèi)存碎片成連續(xù)的空間。

副垃圾回收器

主要負責(zé)新生代的垃圾回收。新生代空間較小,里面的對象一般較??;回收頻繁。

回收機制采用 Scavenge 算法。該算法把新生代空間劃半分為對象區(qū)域空閑區(qū)域。

新加入的對象存到對象區(qū)域,當(dāng)對象區(qū)域快被寫滿時,執(zhí)行一次垃圾回收。在回收過程中,對對象區(qū)域里的對象做標記,標記完成后,把存活的對象復(fù)制到空閑區(qū)域中并有序的排列起來(消除內(nèi)存碎片),把無用的對象清理掉。

復(fù)制完成后,對象區(qū)域和空閑區(qū)域進行角色翻轉(zhuǎn),對象區(qū)域變成空閑區(qū)域,空閑區(qū)域變成對象區(qū)域。這樣這兩塊區(qū)域可以無限重復(fù)使用下去。

復(fù)制操作需要時間成本,因此為了執(zhí)行效率,新生區(qū)的空間一般設(shè)置的比較小。

經(jīng)過兩次垃圾回收依然存活的對象,會被移動到老生區(qū)中,以防止過多的存活對象擠滿新生區(qū)。

主垃圾回收器

主要負責(zé)老生區(qū)的垃圾回收。老生區(qū)的里的對象一般占用空間大(因復(fù)制操作耗時所以不適合使用 Scavenge 算法),存活的時間比較長。

回收機制采用的是 標記-清除(Mark-Sweep)算法。從一組根元素開始,遞歸遍歷這組根元素,在遍歷過程中能到達的元素稱為活動對象,沒有達到的元素判斷標記為垃圾數(shù)據(jù)。

標記完成之后,執(zhí)行清除過程。

如上圖,清除后會產(chǎn)生大量不連續(xù)的內(nèi)存碎片;為了避免內(nèi)存碎片,進化出了另一種算法:標記-整理(Mark-Compact),標記完成后,讓所有存活的對象移向內(nèi)存一端,然后直接清理掉端邊界外的數(shù)據(jù)。

全停頓

Javascript 是運行在主線程上的(單線程),一旦執(zhí)行垃圾回收算法,其他 Javascript 腳本將被阻塞,需要等待垃圾回收完畢才能繼續(xù)執(zhí)行。這種行為叫做全停頓。

如上圖,過長的全停頓將導(dǎo)致頁面卡頓。新生代因其空間小存活對象占用空間小,對全停頓影響不大,老生代的垃圾回收是造成全停頓的主因。為了降低老生代垃圾回收造成的卡頓,V8 將標記過程分為一個個子標記,讓子標記和 Javascript 腳本交替進行,這個解決方案叫做增量標記算法。

以上就是一文詳解Javascript內(nèi)存機制與垃圾回收的詳細內(nèi)容,更多關(guān)于Javascript內(nèi)存機制與垃圾回收的資料請關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • 基于js?+?html2canvas實現(xiàn)網(wǎng)頁放大鏡功能

    基于js?+?html2canvas實現(xiàn)網(wǎng)頁放大鏡功能

    最近接到任務(wù),需實現(xiàn)【網(wǎng)頁】放大鏡的效果,百度搜索?【js?放大鏡】關(guān)鍵字,千篇一律的都是一些仿淘寶/京東等電商網(wǎng)站中查看規(guī)格大圖的效果實現(xiàn),根本無法滿足我的需求,于是自己花了點時間調(diào)研實現(xiàn),在這里分享給大家,感興趣的朋友可以參考下
    2023-12-12
  • 關(guān)于ECMAScript中的原始值和引用值詳解

    關(guān)于ECMAScript中的原始值和引用值詳解

    在ECMAScript中,變量可以存在兩種類型的值,即原始值和引用,這篇這篇文章主要給大家介紹了關(guān)于ECMAScript中的原始值和引用值的相關(guān)資料,需要的朋友可以參考下
    2021-08-08
  • javascript貪吃蛇完整版(源碼)

    javascript貪吃蛇完整版(源碼)

    這篇文章主要是對javascript貪吃蛇完整版(源碼)進行了詳細的分析介紹,需要的朋友可以過來參考下,希望對大家有所幫助
    2013-12-12
  • JS自定義對象創(chuàng)建與簡單使用方法示例

    JS自定義對象創(chuàng)建與簡單使用方法示例

    這篇文章主要介紹了JS自定義對象創(chuàng)建與簡單使用方法,結(jié)合實例形式分析了JavaScript創(chuàng)建與使用自定義對象的相關(guān)操作技巧,需要的朋友可以參考下
    2020-01-01
  • js或jquery實現(xiàn)頁面打印可局部打印

    js或jquery實現(xiàn)頁面打印可局部打印

    這篇文章主要介紹了js或jquery如何實現(xiàn)頁面打印也可局部打印,需要的朋友可以參考下
    2014-03-03
  • 前端接口報錯Required?request?body?is?missing解決辦法

    前端接口報錯Required?request?body?is?missing解決辦法

    這篇文章主要給大家介紹了關(guān)于前端接口報錯Required?request?body?is?missing的解決辦法,文中通過代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2023-12-12
  • 簡單實現(xiàn)js進度條加載效果

    簡單實現(xiàn)js進度條加載效果

    這篇文章主要為大家詳細介紹了如何簡單實現(xiàn)js進度條加載效果,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2017-08-08
  • javascript中檢測變量的類型的代碼

    javascript中檢測變量的類型的代碼

    javascript對于變量的定義、類型的要求都比較松散,這樣既方便,但又容易犯錯。有時候進行必要的類型檢查是必須的。
    2010-12-12
  • 使用js實現(xiàn)動態(tài)背景

    使用js實現(xiàn)動態(tài)背景

    這篇文章主要為大家詳細介紹了使用js實現(xiàn)動態(tài)背景,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2021-11-11
  • js 實現(xiàn)ajax發(fā)送步驟過程詳解

    js 實現(xiàn)ajax發(fā)送步驟過程詳解

    這篇文章主要介紹了js 實現(xiàn)ajax發(fā)送過程詳解,文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友可以參考下
    2019-07-07

最新評論