国产xxxx99真实实拍_久久不雅视频_高清韩国a级特黄毛片_嗯老师别我我受不了了小说

資訊專欄INFORMATION COLUMN

【重溫基礎(chǔ)】22.內(nèi)存管理

Pandaaa / 969人閱讀

摘要:內(nèi)存泄露內(nèi)存泄露概念在計(jì)算機(jī)科學(xué)中,內(nèi)存泄漏指由于疏忽或錯(cuò)誤造成程序未能釋放已經(jīng)不再使用的內(nèi)存。判斷內(nèi)存泄漏,以字段為準(zhǔn)。

本文是 重溫基礎(chǔ) 系列文章的第二十二篇。
今日感受:優(yōu)化學(xué)習(xí)方法。

系列目錄:

【復(fù)習(xí)資料】ES6/ES7/ES8/ES9資料整理(個(gè)人整理)

【重溫基礎(chǔ)】1-14篇

【重溫基礎(chǔ)】15.JS對(duì)象介紹

【重溫基礎(chǔ)】16.JSON對(duì)象介紹

【重溫基礎(chǔ)】17.WebAPI介紹

【重溫基礎(chǔ)】18.相等性判斷

【重溫基礎(chǔ)】19.閉包

【重溫基礎(chǔ)】20.事件

【重溫基礎(chǔ)】21.高階函數(shù)

本章節(jié)復(fù)習(xí)的是JS中的內(nèi)存管理,這對(duì)于我們開發(fā)非常有幫助。

前置知識(shí)
絕大多數(shù)的程序語言,他們的內(nèi)存生命周期基本一致:

分配所需使用的內(nèi)存 ——(分配內(nèi)存

使用分配到的內(nèi)存(讀、寫) ——(使用內(nèi)存

不需要時(shí)將其釋放歸還 ——(釋放內(nèi)存

對(duì)于所有的編程語言,第二部分都是明確的。而第一和第三部分在底層語言中是明確的。
但在像JavaScript這些高級(jí)語言中,大部分都是隱含的,因?yàn)?b>JavaScript具有自動(dòng)垃圾回收機(jī)制(Garbage collected)。
因此在做JavaScript開發(fā)時(shí),不需要關(guān)心內(nèi)存的使用問題,所需內(nèi)存分配和無用內(nèi)存回收,都完全實(shí)現(xiàn)自動(dòng)管理。

1.概述
像C語言這樣的高級(jí)語言一般都有底層的內(nèi)存管理接口,比如 malloc()free()。另一方面,JavaScript創(chuàng)建變量(對(duì)象,字符串等)時(shí)分配內(nèi)存,并且在不再使用它們時(shí)“自動(dòng)”釋放。 后一個(gè)過程稱為垃圾回收。這個(gè)“自動(dòng)”是混亂的根源,并讓JavaScript(和其他高級(jí)語言)開發(fā)者感覺他們可以不關(guān)心內(nèi)存管理。 這是錯(cuò)誤的。
——《MDN JavaScript 內(nèi)存管理》

MDN中的介紹告訴我們,作為JavaScript開發(fā)者,還是需要去了解內(nèi)存管理,雖然JavaScript已經(jīng)給我們做好自動(dòng)管理。

2.JavaScript內(nèi)存生命周期 2.1 分配內(nèi)存

在做JavaScript開發(fā)時(shí),我們定義變量的時(shí)候,JavaScript便為我們完成了內(nèi)存分配:

var num = 100;      // 為數(shù)值變量分配內(nèi)存
var str = "pingan"; // 為字符串變量分配內(nèi)存
var obj = {
    name : "pingan"
};                  // 為對(duì)象變量及其包含的值分配內(nèi)存
var arr = [1, null, "hi"]; // 為數(shù)組變量及其包含的值分配內(nèi)存

function fun(num){
  return num + 2;
};                  // 為函數(shù)(可調(diào)用的對(duì)象)分配內(nèi)存

// 函數(shù)表達(dá)式也能分配一個(gè)對(duì)象
someElement.addEventListener("click", function(){
  someElement.style.backgroundColor = "blue";
}, false);

另外,通過調(diào)用函數(shù),也會(huì)分配內(nèi)存:

// 類型1. 分配對(duì)象內(nèi)存
var date = new Date();   // 分配一個(gè)Date對(duì)象
var elem = document.createElement("div"); // 分配一個(gè)DOM元素

// 類型2. 分配新變量或者新對(duì)象
var str1 = "pingan";
var str2 = str1.substr(0, 3); // str2 是一個(gè)新的字符串

var arr1 = ["hi", "pingan"];
var arr2 = ["hi", "leo"];
var arr3 = arr1.concat(arr2); // arr3 是一個(gè)新的數(shù)組(arr1和arr2連接的結(jié)果)
2.2 使用內(nèi)存

使用內(nèi)存的過程實(shí)際上是對(duì)分配的內(nèi)存進(jìn)行讀取與寫入的操作。
通常表現(xiàn)就是使用定義的值。
讀取與寫入可能是寫入一個(gè)變量或者一個(gè)對(duì)象的屬性值,甚至傳遞函數(shù)的參數(shù)。

var num = 1;
num ++; // 使用已經(jīng)定義的變量,做遞增操作
2.3 釋放內(nèi)存

當(dāng)我們前面定義好的變量或函數(shù)(分配的內(nèi)存)已經(jīng)不需要使用的時(shí)候,便需要釋放掉這些內(nèi)存。這也是內(nèi)存管理中最難的任務(wù),因?yàn)槲覀儾恢朗裁磿r(shí)候這些內(nèi)存不使用。
很好的是,在高級(jí)語言解釋器中,已經(jīng)嵌入“垃圾回收器”,用來跟蹤內(nèi)存的分配和使用,以便在內(nèi)存不使用時(shí)自動(dòng)釋放(這并不是百分百跟蹤到,只是個(gè)近似過程)。

3.垃圾回收機(jī)制

就像前面提到的,“垃圾回收器”只能解決一般情況,接下來我們需要了解主要的垃圾回收算法和它們局限性。

3.1 引用

垃圾回收算法主要依賴于引用的概念。
即在內(nèi)存管理環(huán)境中,一個(gè)對(duì)象如果有權(quán)限訪問另一個(gè)對(duì)象,不論顯式還是隱式,稱為一個(gè)對(duì)象引用另一個(gè)對(duì)象。
例如:一個(gè)JS對(duì)象具有對(duì)它原型的引用(隱式引用)和對(duì)它屬性的引用(顯式引用)。
注意:
這里的對(duì)象,不僅包含JS對(duì)象,也包含函數(shù)作用域(或全局詞法作用域)。

3.2 引用計(jì)數(shù)垃圾收集

這個(gè)算法,把“對(duì)象是否不再需要”定義為:當(dāng)一個(gè)對(duì)象沒有被其他對(duì)象所引用的時(shí)候,回收該對(duì)象。這是最初級(jí)的垃圾收集算法。

var obj = {
    leo : {
        age : 18
    };
};

這里創(chuàng)建2個(gè)對(duì)象,一個(gè)作為leo的屬性被引用,另一個(gè)被分配給變量obj

// 省略上面的代碼
/*
我們將前面的
    {
        leo : {
            age : 18
        };
    };
稱為“這個(gè)對(duì)象”
*/
var obj2 = obj;  // obj2變量是第二個(gè)對(duì)“這個(gè)對(duì)象”的引用
obj = "pingan";  // 將“這個(gè)對(duì)象”的原始是引用obj換成obj2

var leo2 = obj2.leo;  // 引用“這個(gè)對(duì)象”的leo屬性

可以看出,現(xiàn)在的“這個(gè)對(duì)象”已經(jīng)有2個(gè)引用,一個(gè)是obj2,另一個(gè)是leo2

obj2 = "hi"; 
// 將obj2變成零引用,因此,obj2可以被垃圾回收
// 但是它的屬性leo還在被leo2對(duì)象引用,所以還不能回收

leo2 = null;
// 將leo變成零引用,這樣obj2和leo2都可以被垃圾回收

這個(gè)算法有個(gè)限制
無法處理循環(huán)引用。即兩個(gè)對(duì)象創(chuàng)建時(shí)相互引用形成一個(gè)循環(huán)。

function fun(){
    var obj1 = {}, obj2 = {};
    obj1.leo = obj2;  // obj1引用obj2
    obj2.leo = obj1;  // obj2引用obj1
    return "hi pingan";
}
fun();

可以看出,它們被調(diào)用之后,會(huì)離開函數(shù)作用域,已經(jīng)沒有用了可以被回收,然而引用計(jì)數(shù)算法考慮到它們之間相互至少引用一次,所以它們不會(huì)被回收。

實(shí)際案例
在IE6,7中,使用引用計(jì)數(shù)方式對(duì)DOM對(duì)象進(jìn)行垃圾回收,常常造成對(duì)象被循環(huán)引用導(dǎo)致內(nèi)存泄露:

var obj;
window.onload = function(){
    obj = document.getElementById("myId");
    obj.leo = obj;
    obj.data = new Array(100000).join("");
};

可以看出,DOM元素obj中的leo屬性引用了自己obj,造成循環(huán)引用,若該屬性(leo)沒有移除或設(shè)置為null,垃圾回收器總是且至少有一個(gè)引用,并一直占用內(nèi)存,即使從DOM樹刪除,如果這個(gè)DOM元素含大量數(shù)據(jù)(如data屬性)則會(huì)導(dǎo)致占用內(nèi)存永遠(yuǎn)無法釋放,出現(xiàn)內(nèi)存泄露。

3.3 標(biāo)記清除算法

這個(gè)算法,將“對(duì)象是否不再需要”定義為:對(duì)象是否可以獲得。

標(biāo)記清除算法,是假定設(shè)置一個(gè)根對(duì)象(root),在JS中是全局對(duì)象。垃圾回收器定時(shí)找所有從根開始引用的對(duì)象,然后再找這些對(duì)象引用的對(duì)象...直到找到所有可以獲得的對(duì)象搜集所有不能獲得的對(duì)象

它比引用計(jì)數(shù)垃圾收集更好,因?yàn)椤坝辛阋玫膶?duì)象”總是不可獲得的,但是相反卻不一定,參考“循環(huán)引用”。

循環(huán)引用不再是問題:

function fun(){
    var obj1 = {}, obj2 = {};
    obj1.leo = obj2;  // obj1引用obj2
    obj2.leo = obj1;  // obj2引用obj1
    return "hi pingan";
}
fun();

還是這個(gè)代碼,可以看出,使用標(biāo)記清除算法來看,函數(shù)調(diào)用之后,兩個(gè)對(duì)象無法從全局對(duì)象獲取,因此將被回收。相同的,下面案例,一旦 obj 和其事件處理無法從根獲取到,他們將會(huì)被垃圾回收器回收。

var obj;
window.onload = function(){
    obj = document.getElementById("myId");
    obj.leo = obj;
    obj.data = new Array(100000).join("");
};

注意: 那些無法從根對(duì)象查詢到的對(duì)象都將被清除。

3.4 個(gè)人小結(jié)

在日常開發(fā)中,應(yīng)該注意及時(shí)切斷需要回收對(duì)象與根的聯(lián)系,雖然標(biāo)記清除算法已經(jīng)足夠強(qiáng)壯,就像下面代碼:

var obj,ele=document.getElementById("myId");
obj.div = document.createElement("div");
ele.appendChild(obj.div);
// 刪除DOM元素
ele.removeChild(obj.div);

如果我們只是做小型項(xiàng)目開發(fā),JS用的比較少的話,內(nèi)存管理可以不用太在意,但是如果是大項(xiàng)目(SPA,服務(wù)器或桌面應(yīng)用),那就需要考慮好內(nèi)存管理問題了。

4.內(nèi)存泄露(Memory Leak) 4.1 內(nèi)存泄露概念
在計(jì)算機(jī)科學(xué)中,內(nèi)存泄漏指由于疏忽或錯(cuò)誤造成程序未能釋放已經(jīng)不再使用的內(nèi)存。內(nèi)存泄漏并非指內(nèi)存在物理上的消失,而是應(yīng)用程序分配某段內(nèi)存后,由于設(shè)計(jì)錯(cuò)誤,導(dǎo)致在釋放該段內(nèi)存之前就失去了對(duì)該段內(nèi)存的控制,從而造成了內(nèi)存的浪費(fèi)。 ——維基百科

其實(shí)簡單理解:一些不再使用的內(nèi)存無法被釋放
當(dāng)內(nèi)存占用越來越多,不僅影響系統(tǒng)性能,嚴(yán)重的還會(huì)導(dǎo)致進(jìn)程奔潰。

4.2 內(nèi)存泄露案例

全局變量

未定義的變量,會(huì)被定義到全局,當(dāng)頁面關(guān)閉才會(huì)銷毀,這樣就造成內(nèi)存泄露。如下:

function fun(){
    name = "pingan";
};

未銷毀的定時(shí)器和回調(diào)函數(shù)

如果這里舉一個(gè)定時(shí)器的案例,如果定時(shí)器沒有回收,則不僅整個(gè)定時(shí)器無法被內(nèi)存回收,定時(shí)器函數(shù)的依賴也無法回收:

var data = {};
setInterval(function(){
    var render = document.getElementById("myId");
    if(render){
        render.innderHTML = JSON.stringify(data);
    }
}, 1000);

閉包

var str = null;
var fun = function(){
    var str2 = str;
    var unused = function(){
        if(str2) console.log("is unused");
    };
    str = {
        my_str = new Array(100000).join("--");
        my_fun = function(){
            console.log("is my_fun");
        };
    };
};
setInterval(fun, 1000);

定時(shí)器中每次調(diào)用funstr都會(huì)獲得一個(gè)包含巨大的數(shù)組和一個(gè)對(duì)于新閉包my_fun的對(duì)象,并且unused是一個(gè)引用了str2的閉包。
整個(gè)案例中,閉包之間共享作用域,盡管unused可能一直沒有調(diào)用,但my_fun可能被調(diào)用,就會(huì)導(dǎo)致內(nèi)存無法回收,內(nèi)存增長導(dǎo)致泄露。

DOM引用

當(dāng)我們把DOM的引用保存在一個(gè)數(shù)組或Map中,即使移除了元素,但仍然有引用,導(dǎo)致無法回收內(nèi)存。例如:

var ele = {
    img : document.getElementById("my_img")
};
function fun(){
    ele.img.src = "http://www.baidu.com/1.png";
};
function foo(){
    document.body.removeChild(document.getElementById("my_img"));
};

即使foo方法將my_img元素移除,但fun仍有引用,無法回收。

4.3 內(nèi)存泄露識(shí)別方法

瀏覽器

通過Chrome瀏覽器查看內(nèi)存占用:

步驟如下:

打開開發(fā)者工具,選擇 Timeline 面板

在頂部的Capture字段里面勾選 Memory

點(diǎn)擊左上角的錄制按鈕

在頁面上進(jìn)行各種操作,模擬用戶的使用情況

一段時(shí)間后,點(diǎn)擊對(duì)話框的 stop 按鈕,面板上就會(huì)顯示這段時(shí)間的內(nèi)存占用情況

如果內(nèi)存占用基本平穩(wěn),接近水平,就說明不存在內(nèi)存泄漏。

反之,就是內(nèi)存泄漏了。

命令行

命令行可以使用 Node 提供的process.memoryUsage方法。

console.log(process.memoryUsage());
// { rss: 27709440,
//  heapTotal: 5685248,
//  heapUsed: 3449392,
//  external: 8772 }

process.memoryUsage返回一個(gè)對(duì)象,包含了 Node 進(jìn)程的內(nèi)存占用信息。該對(duì)象包含四個(gè)字段,單位是字節(jié),含義如下。

rss(resident set size):所有內(nèi)存占用,包括指令區(qū)和堆棧。

heapTotal:"堆"占用的內(nèi)存,包括用到的和沒用到的。

heapUsed:用到的堆的部分。

external: V8 引擎內(nèi)部的 C++ 對(duì)象占用的內(nèi)存。

判斷內(nèi)存泄漏,以heapUsed字段為準(zhǔn)。

參考文章

MDN JavaScript指南 內(nèi)存管理

精讀《JS 中的內(nèi)存管理》

阮一峰老師JavaScript 內(nèi)存泄漏教程

本部分內(nèi)容到這結(jié)束

Author 王平安
E-mail pingan8787@qq.com
博 客 www.pingan8787.com
微 信 pingan8787
每日文章推薦 https://github.com/pingan8787...
JS小冊 js.pingan8787.com
微信公眾號(hào) 前端自習(xí)課

文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請注明本文地址:http://m.specialneedsforspecialkids.com/yun/101725.html

相關(guān)文章

  • 重溫JS基礎(chǔ)--變量、作用域和內(nèi)存問題

    摘要:作用域鏈?zhǔn)潜WC對(duì)執(zhí)行環(huán)境有權(quán)訪問的所有變量和函數(shù)的有序訪問。如上,包含的作用域鏈包含它自己的變量對(duì)象和全局環(huán)境的變量對(duì)象,為什么能在函數(shù)內(nèi)訪問,這就是通過作用域鏈找的。 前言JavaScript的變量類型是弱類型的,在特定的時(shí)間內(nèi)保存一個(gè)特定的值,變量的值和數(shù)據(jù)類型可以在腳本的生命周期內(nèi)隨意改變。 1. 基本類型和引用類型的值 JavaScript包含兩種不同類型的值:基本類型和引用類...

    huaixiaoz 評(píng)論0 收藏0
  • 重溫基礎(chǔ)】9.正則表達(dá)式

    摘要:前置知識(shí)中的正則表達(dá)式是用來匹配字符串中指定字符組合的模式。另外需要記住正則表達(dá)式也是對(duì)象。在正則表達(dá)式創(chuàng)建時(shí)更新,不執(zhí)行。替換與正則表達(dá)式匹配的子串。查找以十六進(jìn)制數(shù)規(guī)定的字符。正則表達(dá)式拓展介紹在中有兩種情況。 本文是 重溫基礎(chǔ) 系列文章的第九篇。 今日感受:時(shí)間管理-角色管理法。 系列目錄: 【復(fù)習(xí)資料】ES6/ES7/ES8/ES9資料整理(個(gè)人整理) 【重溫基礎(chǔ)】1.語...

    ispring 評(píng)論0 收藏0
  • 重溫基礎(chǔ)】19.閉包

    摘要:系列目錄復(fù)習(xí)資料資料整理個(gè)人整理重溫基礎(chǔ)篇重溫基礎(chǔ)對(duì)象介紹重溫基礎(chǔ)對(duì)象介紹重溫基礎(chǔ)介紹重溫基礎(chǔ)相等性判斷本章節(jié)復(fù)習(xí)的是中的關(guān)于閉包,這個(gè)小哥哥呀,看看。這里隨著閉包函數(shù)的結(jié)束,執(zhí)行環(huán)境銷毀,變量回收。 本文是 重溫基礎(chǔ) 系列文章的第十九篇。今日感受:將混亂的事情找出之間的聯(lián)系,也是種能力。 系列目錄: 【復(fù)習(xí)資料】ES6/ES7/ES8/ES9資料整理(個(gè)人整理) 【重溫基礎(chǔ)】...

    nanfeiyan 評(píng)論0 收藏0
  • 重溫基礎(chǔ)】12.使用對(duì)象

    摘要:本文是重溫基礎(chǔ)系列文章的第十二篇。注意對(duì)象的名稱,對(duì)大小寫敏感。基礎(chǔ)用法第一個(gè)參數(shù)是目標(biāo)對(duì)象,后面參數(shù)都是源對(duì)象。用途遍歷對(duì)象屬性。用途將對(duì)象轉(zhuǎn)為真正的結(jié)構(gòu)。使用場景取出參數(shù)對(duì)象所有可遍歷屬性,拷貝到當(dāng)前對(duì)象中。類似方法合并兩個(gè)對(duì)象。 本文是 重溫基礎(chǔ) 系列文章的第十二篇。 今日感受:需要總結(jié)下2018。 這幾天,重重的感冒發(fā)燒,在家休息好幾天,傷···。 系列目錄: 【復(fù)習(xí)資料...

    garfileo 評(píng)論0 收藏0
  • 重溫JS基礎(chǔ)--引用類型(二)

    摘要:創(chuàng)建一個(gè)日期對(duì)象中國標(biāo)準(zhǔn)時(shí)間在調(diào)用構(gòu)造函數(shù)而不傳參數(shù)的情況下,新創(chuàng)建的對(duì)象自動(dòng)獲得當(dāng)前日期和時(shí)間。日期格式化方法類型還有一些專門用于將日期格式化為字符串的方法中國標(biāo)準(zhǔn)時(shí)間下午以上的這些方法都會(huì)根據(jù)系統(tǒng)環(huán)境而異。 咱們接著上面一篇繼續(xù)~ 1. Date類型 JavaScript中的Date類型使用自UTC時(shí)間,1970年1月1日零時(shí)開始的毫秒數(shù)來保存日期。創(chuàng)建一個(gè)日期對(duì)象: var no...

    NusterCache 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

最新活動(dòng)
閱讀需要支付1元查看
<