日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 前端技术 > javascript >内容正文

javascript

JS高级——内存管理和闭包

發(fā)布時(shí)間:2024/7/5 javascript 34 豆豆
生活随笔 收集整理的這篇文章主要介紹了 JS高级——内存管理和闭包 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

0、預(yù)備知識(shí)

0.1 認(rèn)識(shí)內(nèi)存管理

不管什么樣的編程語言,在代碼的執(zhí)行過程中都是需要給它分配內(nèi)存的,不同的是某些編程語言需要我們自己手動(dòng)的管理內(nèi)存,某些編程語言會(huì)可以自動(dòng)幫助我們管理內(nèi)存:

不管以什么樣的方式來管理內(nèi)存,內(nèi)存的管理都會(huì)有如下的生命周期:

  • 第一步:分配申請你需要的內(nèi)存(申請);
  • 第二步:使用分配的內(nèi)存(存放一些東西,比如對象等);
  • 第三步:不需要使用時(shí),對其進(jìn)行釋放;

不同的編程語言對于第一步和第三步會(huì)有不同的實(shí)現(xiàn):

  • 手動(dòng)管理內(nèi)存:比如C、C++,包括早期的OC,都是需要手動(dòng)來管理內(nèi)存的申請和釋放的(malloc和free函數(shù));
  • 自動(dòng)管理內(nèi)存:比如Java、JavaScript、Python、Swift、Dart等,它們有自動(dòng)幫助我們管理內(nèi)存;

我們可以知道JavaScript通常情況下是不需要手動(dòng)來管理的。

0.2 JS的內(nèi)存管理

JavaScript會(huì)在定義變量時(shí)為我們分配內(nèi)存。但是內(nèi)存分配方式是一樣的嗎?

  • JS對于基本數(shù)據(jù)類型內(nèi)存的分配會(huì)在執(zhí)行時(shí),直接在棧空間進(jìn)行分配;
  • JS對于復(fù)雜數(shù)據(jù)類型內(nèi)存的分配會(huì)在堆內(nèi)存中開辟一塊空間,并且將這塊空間的指針返回值變量引用;

0.3 JS的垃圾回收

因?yàn)閮?nèi)存的大小是有限的,所以當(dāng)內(nèi)存不再需要的時(shí)候,我們需要對其進(jìn)行釋放,以便騰出更多的內(nèi)存空間。

在手動(dòng)管理內(nèi)存的語言中,我們需要通過一些方式自己來釋放不再需要的內(nèi)存,比如free函數(shù):

  • 但是這種管理的方式其實(shí)非常的低效,影響我們編寫邏輯的代碼的效率;
  • 并且這種方式對開發(fā)者的要求也很高,并且一不小心就會(huì)產(chǎn)生內(nèi)存泄露;

所以大部分現(xiàn)代的編程語言都是有自己的垃圾回收機(jī)制:

  • 垃圾回收的英文是Garbage Collection,簡稱GC;
  • 對于那些不再使用的對象,我們都稱之為是垃圾,它需要被回收,以釋放更多的內(nèi)存空間;
  • 而我們的語言運(yùn)行環(huán)境,比如Java的運(yùn)行環(huán)境JVM,JavaScript的運(yùn)行環(huán)境js引擎都會(huì)內(nèi)存 垃圾回收器;
  • 垃圾回收器我們也會(huì)簡稱為GC,所以在很多地方你看到GC其實(shí)指的是垃圾回收器;

但是這里又出現(xiàn)了另外一個(gè)很關(guān)鍵的問題:GC怎么知道哪些對象是不再使用的呢?

  • 這里就要用到GC的算法了

0.3.1 常見的GC算法 – 引用計(jì)數(shù)

引用計(jì)數(shù):

  • 當(dāng)一個(gè)對象有一個(gè)引用指向它時(shí),那么這個(gè)對象的引用就+1,當(dāng)一個(gè)對象的引用為0時(shí),這個(gè)對象就可以被銷毀掉;
  • 這個(gè)算法有一個(gè)很大的弊端就是會(huì)產(chǎn)生循環(huán)引用,比如如下:循環(huán)引用的兩個(gè)obj無法被GC回收

0.3.2 常見的GC算法 – 標(biāo)記清除

標(biāo)記清除:

  • 這個(gè)算法是設(shè)置一個(gè)根對象(root object)(在瀏覽器中,這個(gè)根對象就是全局對象GO),垃圾回收器會(huì)定期從這個(gè)根開始,找所有從根開始有引用到的對象,對于哪些沒有引用到的對象,就認(rèn)為是不可用的對象;
  • 這個(gè)算法可以很好的解決循環(huán)引用的問題;

    JS引擎比較廣泛的采用的就是標(biāo)記清除算法,當(dāng)然類似于V8引擎為了進(jìn)行更好的優(yōu)化,它在算法的實(shí)現(xiàn)細(xì)節(jié)上也會(huì)結(jié)合一些其他的算法。

一、JS中閉包的定義

  • 一個(gè)普通的函數(shù)function,如果它可以訪問外層作用于的自由變量,那么這個(gè)函數(shù)就是一個(gè)閉包;
  • 從廣義的角度來說:JavaScript中的函數(shù)都是閉包;
  • 從狹義的角度來說:JavaScript中一個(gè)函數(shù),如果訪問了外層作用于的變量,那么它是一個(gè)閉包;

二、閉包的訪問過程(內(nèi)存圖)

如果我們編寫了如下的代碼,它一定是形成了閉包的:

2.1 創(chuàng)建GO對象,創(chuàng)建全局執(zhí)行上下文并壓入執(zhí)行上下文棧中

2.2 執(zhí)行foo(),創(chuàng)建foo函數(shù)的AO對象

2.3 創(chuàng)建foo函數(shù)執(zhí)行上下文并壓入執(zhí)行上下文棧中,然后開始執(zhí)行foo函數(shù)內(nèi)的代碼

2.4 foo函數(shù)執(zhí)行結(jié)束,將foo函數(shù)執(zhí)行上下文彈出棧

2.5 執(zhí)行fn()函數(shù),創(chuàng)建fn函數(shù)(bar)的AO對象,創(chuàng)建fn函數(shù)(bar)的函數(shù)執(zhí)行上下文并壓入執(zhí)行上下文棧中

2.6 fn函數(shù)(bar)執(zhí)行完成,將fn函數(shù)(bar)的函數(shù)執(zhí)行上下文彈出棧,垃圾回收器銷毀bar函數(shù)的AO對象

注意:在此之前,是存在內(nèi)存泄漏的,因?yàn)閒oo函數(shù)執(zhí)行結(jié)束了,但是foo函數(shù)的AO對象并沒有被銷毀(因?yàn)橛衎ar函數(shù)對象指向它)。foo函數(shù)的AO對象是應(yīng)該被銷毀的但沒被銷毀,所以說存在內(nèi)存泄露!

2.7 執(zhí)行fn = null,由于fn變量指向null,bar函數(shù)的AO對象沒有任何變量指向,所以垃圾回收器會(huì)銷毀bar函數(shù)的AO對象

2.8 由于bar函數(shù)的AO對象被垃圾回收器銷毀,foo函數(shù)的AO對象沒有任何變量指向,也會(huì)被垃圾回收器銷毀

2.9 指向foo = null,foo變量指向null,不再指向foo函數(shù)對象

2.10 由于foo函數(shù)對象沒有任何變量指向,所以會(huì)被垃圾回收器銷毀

三、AO不使用的屬性

我們來研究一個(gè)問題:AO對象不會(huì)被銷毀時(shí),是否里面的所有屬性都不會(huì)被釋放?

  • 下面這段代碼中name屬于閉包的父作用域里面的變量;
  • 我們知道形成閉包之后count一定不會(huì)被銷毀掉,那么name是否會(huì)被銷毀掉呢?
  • 這里我打上了斷點(diǎn),我們可以在瀏覽器上看看結(jié)果;

答案:AO不使用的屬性name是會(huì)被銷毀的

總結(jié)

以上是生活随笔為你收集整理的JS高级——内存管理和闭包的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。