avaScript 數組方法
JavaScript 數組的力量隱藏在數組方法中。
JavaScript 方法 toString() 把數組轉換為數組值(逗號分隔)的字符串。
var fruits=["Banana", "Orange", "Apple", "Mango"];
document.getElementById("demo").innerHTML=fruits.toString();
結果
Banana,Orange,Apple,Mango
親自試一試
join() 方法也可將所有數組元素結合為一個字符串。
它的行為類似 toString(),但是您還可以規定分隔符:
var fruits=["Banana", "Orange","Apple", "Mango"];
document.getElementById("demo").innerHTML=fruits.join(" * ");
結果
Banana * Orange * Apple * Mango
親自試一試
在處理數組時,刪除元素和添加新元素是很簡單的。
Popping 和 Pushing 指的是:
從數組彈出項目,或向數組推入項目。
pop() 方法從數組中刪除最后一個元素:
var fruits=["Banana", "Orange", "Apple", "Mango"];
fruits.pop(); // 從 fruits 刪除最后一個元素("Mango")
親自試一試
pop() 方法返回“被彈出”的值:
var fruits=["Banana", "Orange", "Apple", "Mango"];
var x=fruits.pop(); // x 的值是 "Mango"
親自試一試
push() 方法(在數組結尾處)向數組添加一個新的元素:
var fruits=["Banana", "Orange", "Apple", "Mango"];
fruits.push("Kiwi"); // 向 fruits 添加一個新元素
親自試一試
push() 方法返回新數組的長度:
var fruits=["Banana", "Orange", "Apple", "Mango"];
var x=fruits.push("Kiwi"); // x 的值是 5
親自試一試
位移與彈出等同,但處理首個元素而不是最后一個。
shift() 方法會刪除首個數組元素,并把所有其他元素“位移”到更低的索引。
var fruits=["Banana", "Orange", "Apple", "Mango"];
fruits.shift(); // 從 fruits 刪除第一個元素 "Banana"
親自試一試
shift() 方法返回被“位移出”的字符串:
var fruits=["Banana", "Orange", "Apple", "Mango"];
fruits.shift(); // 返回 "Banana"
親自試一試
unshift() 方法(在開頭)向數組添加新元素,并“反向位移”舊元素:
var fruits=["Banana", "Orange", "Apple", "Mango"];
fruits.unshift("Lemon"); // 向 fruits 添加新元素 "Lemon"
親自試一試
unshift() 方法返回新數組的長度。
var fruits=["Banana", "Orange", "Apple", "Mango"];
fruits.unshift("Lemon"); // 返回 5
親自試一試
通過使用它們的索引號來訪問數組元素:
數組索引(下標)以 0 開始。[0] 是第一個數組元素,[1] 是第二個,[2] 是第三個 ...
var fruits=["Banana", "Orange", "Apple", "Mango"];
fruits[0]="Kiwi"; // 把 fruits 的第一個元素改為 "Kiwi"
親自試一試
length 屬性提供了向數組追加新元素的簡易方法:
var fruits=["Banana", "Orange", "Apple", "Mango"];
fruits[fruits.length]="Kiwi"; // 向 fruits 追加 "Kiwi"
親自試一試
既然 JavaScript 數組屬于對象,其中的元素就可以使用 JavaScript delete 運算符來刪除:
var fruits=["Banana", "Orange", "Apple", "Mango"];
delete fruits[0]; // 把 fruits 中的首個元素改為 undefined
親自試一試
使用 delete 會在數組留下未定義的空洞。請使用 pop() 或 shift() 取而代之。
splice() 方法可用于向數組添加新項:
var fruits=["Banana", "Orange", "Apple", "Mango"];
fruits.splice(2, 0, "Lemon", "Kiwi");
親自試一試
第一個參數(2)定義了應添加新元素的位置(拼接)。
第二個參數(0)定義應刪除多少元素。
其余參數(“Lemon”,“Kiwi”)定義要添加的新元素。
splice() 方法返回一個包含已刪除項的數組:
var fruits=["Banana", "Orange", "Apple", "Mango"];
fruits.splice(2, 2, "Lemon", "Kiwi");
親自試一試
通過聰明的參數設定,您能夠使用 splice() 在數組中不留“空洞”的情況下移除元素:
var fruits=["Banana", "Orange", "Apple", "Mango"];
fruits.splice(0, 1); // 刪除 fruits 中的第一個元素
親自試一試
第一個參數(0)定義新元素應該被添加(接入)的位置。
第二個參數(1)定義應該刪除多個元素。
其余參數被省略。沒有新元素將被添加。
concat() 方法通過合并(連接)現有數組來創建一個新數組:
var myGirls=["Cecilie", "Lone"];
var myBoys=["Emil", "Tobias", "Linus"];
var myChildren=myGirls.concat(myBoys); // 連接 myGirls 和 myBoys
親自試一試
concat() 方法不會更改現有數組。它總是返回一個新數組。
concat() 方法可以使用任意數量的數組參數:
var arr1=["Cecilie", "Lone"];
var arr2=["Emil", "Tobias", "Linus"];
var arr3=["Robin", "Morgan"];
var myChildren=arr1.concat(arr2, arr3); // 將arr1、arr2 與 arr3 連接在一起
親自試一試
concat() 方法也可以將值作為參數:
var arr1=["Cecilie", "Lone"];
var myChildren=arr1.concat(["Emil", "Tobias", "Linus"]);
親自試一試
slice() 方法用數組的某個片段切出新數組。
本例從數組元素 1 ("Orange")開始切出一段數組:
var fruits=["Banana", "Orange", "Lemon", "Apple", "Mango"];
var citrus=fruits.slice(1);
親自試一試
slice() 方法創建新數組。它不會從源數組中刪除任何元素。
本例從數組元素 3 ("Apple")開始切出一段數組:
var fruits=["Banana", "Orange", "Lemon", "Apple", "Mango"];
var citrus=fruits.slice(3);
親自試一試
slice() 可接受兩個參數,比如 (1, 3)。
該方法會從開始參數選取元素,直到結束參數(不包括)為止。
var fruits=["Banana", "Orange", "Lemon", "Apple", "Mango"];
var citrus=fruits.slice(1, 3);
親自試一試
如果結束參數被省略,比如第一個例子,則 slice() 會切出數組的剩余部分。
var fruits=["Banana", "Orange", "Lemon", "Apple", "Mango"];
var citrus=fruits.slice(2);
親自試一試
如果需要原始值,則 JavaScript 會自動把數組轉換為字符串。下面兩個例子將產生相同的結果:
var fruits=["Banana", "Orange", "Apple", "Mango"];
document.getElementById("demo").innerHTML=fruits.toString();
親自試一試
var fruits=["Banana", "Orange", "Apple", "Mango"];
document.getElementById("demo").innerHTML=fruits;
親自試一試
所有 JavaScript 對象都擁有 toString() 方法。
i,朋友,您來啦。帶上小板凳,我們一起瞅一瞅今天的話題。
undefined、null、boolean、number、string、symbol和BigInt。
BigInt:專治各種不服的大整數,海納百川、超級無敵都不夠形容它。
symbol:你我Ta可以共享一個名字,但就是不一樣,橫空出世時,就有全宇宙唯一標識。
對象(普通對象、日期對象、錯誤對象等)、數組、函數、正則表達式、Promise、Map、Set、WeakMap、WeakSet、Generator、Proxy、……。
掌握了復雜類型,就擁有了魔法,有了魔法就能駕馭編程的洪流。[呲牙]
typeof 返回一個字符串,表示變量或表達式的類型。需要注意的是,typeof 在大多數情況下,針對某些類型都會返回 "object",而不是具體的類型名稱。
instanceof 運算符用于檢測構造函數的 prototype 屬性是否出現在某個實例對象的原型鏈上。
Object.prototype.toString.call()
此方式返回一個表示該對象的字符串,其中包括了對象的類型信息。這種方法可以識別出更具體的類型。
關注作者:關注有趣的前端編程。
希望本文能夠對您有所幫助,感謝您的閱讀!
人人為我,我為人人,謝謝您的瀏覽,讓我們一起加油吧。
多開發者可能平時并不關心自己維護的頁面是否存在內存泄漏,原因可能是剛開始簡單的頁面內存泄漏的速度很緩慢,在造成嚴重卡頓之前可能就被用戶刷新了,問題也就被隱藏了,但是隨著頁面越來越復雜,尤其當你的頁面是 SAP 方式交互時,內存泄漏的隱患便越來越嚴重,直到突然有一天用戶反饋說:“操作一會兒頁面就卡住不動了,也不知道為什么,以前不這樣的呀”。
這篇文章通過一些簡單的例子介紹內存泄漏的調查方法、總結內存泄漏出現的原因和常見情況,并針對每種情況總結如何避免內存泄漏。希望能對大家有所幫助。
先看一個簡單的例子,下面是這個例子對應的代碼:
代碼 1
代碼 1 的邏輯很簡單:點擊“add date”按鈕時會向 dateAry 數組中 push 3000 個 new Date 對象,點擊“clear”按鈕時將 dateAry 清空。很明顯,“add date”操作會造成內存占用不斷增長,如果將這個邏輯用在實際應用中便會造成內存泄漏(不考慮故意將代碼邏輯設計成這樣的情況),下面我們看一下如何調查這種內存增長出現的原因以及如何找出內存泄漏點。
1 heap snapshot
為了避免瀏覽器插件的干擾,我們在 chrome 中新建一個無痕窗口打開上述代碼。然后在 chrome 的 devtools 中的 Memory 工具中找到 “Heap Snapshot”工具,點擊左上角的錄制按鈕錄制一個 Snapshot,然后點擊“add date”按鈕,在手動觸發 GC(Garbage Collect)之后,再次錄制一個 Snapshot,反復執行上述操作若干次,像圖 1 中操作的那樣,得到一系列的 Snapshot。
圖 1 錄制 Snapshot
圖 2 是我們剛剛得到的 Snapshot 組,其中的第一個是頁面初始加載的時候錄制的,不難發現,從第二個開始,每個 Snapshot 相比于上一個其大小都增加了約 200KB,我們點擊選擇 Snapshot 2,在 class filter 輸入框中處輸入 date,可以得到 Snapshot 2 中所有被 Date 構造器構造出來的 JS 對象,也就是 Date 對象,這里看到的構造器跟瀏覽器內部的實現有關,不必跟 JS 的對象對應。
選中一個 Date 對象,在下面的面板中可以看到所選對象的持有鏈以及相關持有對象的內存的保留大小(Retained Size),從圖中可以看出選中的 Date 對象是 Array 的第 1 個元素(index 從 0 開始),而這個 Array 的持有者是 system/Context 上下文中的 dateAry,system/Context 上下文就是代碼中 script 標簽的上下文,我們可以看到在這個 dataAry 的保留大小是 197KB,我們再切到 Snapshot 3,用相同的方式查看內存持有和大小,可以發現 Snapshot 3 中的 dataAry 的保留大小變成了 386KB,相比于 Snapshot 2 增漲了約 200KB!逐一比較后面的 Snapshot 4、5 后也能得到相同的對比結果,即下一個 Snapshot 中的 dateAry 比上一個的保留大小大約 200KB。
圖 2 錄制的 Snapshot 組
參考【代碼 1】我們可以知道,“add date”按鈕在被點擊時,會向 dateAry 數組中 push 3000 個新的 Date 對象,而在圖 2 中的 Date 構造器的右側可以看到這 3000 個 Date 對象(Date x 3000),它對應的正式我們的循環創建的那 3000 個 Date 對象。綜合上面的操作我們可以知道,chorome devtools 中的 Memroy 的 Heap Snapshot 工具可以錄制某一個時刻的所有內存對象,也就是一個“快照”,快照中按“構造器”分組,展示了所有被記錄下來的 JS 對象。
如果這個頁面是一個實際服務于用戶的網站的某個頁面話(用戶可能非常頻繁的點擊“add date”按鈕,作者可能想記錄用戶點擊的次數?也許吧,雖然我也不知道他什么要這么做)隨著用戶使用時間的增長,“add date”按鈕的反應就會越來越慢,整體頁面也隨之越來越卡,原因除了系統的內存資源被占用之外,還有 GC 的頻率和時長增長,如圖 3 所示,因為 GC 執行的過程中 JS 的執行是被暫停的,所以頁面就會呈現出越來越卡的樣子。
圖 3 Performance 錄制的 GC 占比
圖 4 chrome 的任務管理器
最終:
圖 5 內存占用過高導致瀏覽器崩潰
那么,在這個“實際”的場景下,如何找出那“作祟”的 3000 個 Date 對象呢?我們首先想到的應該是就是:之前不是錄制了好多個 Snapshot 嗎?可不可以把它們做對比找到“差異”呢,從差異中找到增長的地方不就行了?思路非常正確,在此之前我們再分析一下這幾個 Snapshot:每次點擊“add date”按鈕、手動觸發 GC、得到的 Snapshot 的大小相比上一次都有所增加,如果這種內存的增長現象不符合“預期”的話(顯然在這個“實際”的例子中是不符合預期的),那么這里就有很大的嫌疑存在內存泄漏。
這個時候我們選中 Snapshot 2,在圖 2 所示的 " Summary" 處選擇“Comparison”,在右側的 "All objects" 處選擇 Snapshot 1,這樣一來,Constructor 里展示便是 Snapshot 1 和 Snapshot 2 的對比,通過觀察不難發現,圖中的 +144KB 最值得懷疑,于是我們選中它的構造器 Date,展開選中任意子項看詳情,發現其是被 Array 構造器構造出來的 dateAry 持有的(即 dateAry 中的一員),并且 dateAry 被三個地方持有,其中系統內部的 array 我們不用理會,圖 6 中寫有 "context in ()" 地方給了我們持有 dateAry 的 context 所在的位置,點擊便可以跳到代碼所在的位置了,整個操作如圖 6 所示:
圖 6 定位代碼位置
這里有一個值得注意的地方,圖 6 中的 “context in () @449305” 中的 "()",這里之所以展示為了 "()" 是因為代碼中用了“匿名函數”(代碼 2 中第 2 行的箭頭函數):
// 【寫入 date】
pushDate.addEventListener("click", ()=> {
dateCount.innerHTML=`${++dateNum}`;
for (let j=0; j < 3000; ++j) {
dateAry.push(new Date());
}
});
代碼 2 匿名函數
但是如果我們給函數起一個名字,如下面的代碼所示,也就是如果我們使用具名函數(代碼3 第 2 行函數 add)或者將函數賦值給一個變量并使用這個變量(第 10 和 18 行的行為)的時候,devtools 中都可以看到相應的函數的名字,這也就可以幫助我們更好的定位代碼,如圖 7 所示。
// 【寫入 date】
pushDate.addEventListener("click", function add() {
dateCount.innerHTML=`${++dateNum}`;
for (let j=0; j < 3000; ++j) {
dateAry.push(new Date());
}
});
const clear=document.querySelector(".clear");
const doClear=function () {
dateAry=[];
dateCount.innerHTML="0";
};
// 【回收內存】
clear.addEventListener("click", doClear);
代碼 3 具名函數
圖 7 具名函數方便定位
這樣我們便找到了代碼可疑的地方,只需要將代碼的作者抓過來對著他一頓“分析”這個內存泄漏的問題基本就水落石出了。
其實,Snapshot 除了“Comparison”之外還有一個更便捷的用于對比的入口,在這里直接可以看到在錄制 Snapshot 1 和 Snapshot 2 兩個時間點之間被分配出來的內存,用這種方式也可以定位到那個可疑的 Date x 3000:
圖 8 Snapshot 比較器
上文件介紹的是用 Heap Snapshot 尋找內存泄漏點的方法,這個方法的優點:可以錄制多個 Snapshot,然后方便的兩兩比較,并且能看到 Snapshot 中的全量內存,這一點是下文要講的“Allocation instrumentation on timeline”方法不具備的,并且這種方法可以更加方便地查找后面會講的因 Detached Dom 導致的內存泄漏。
2 Allocation instrumentation on timeline
但是,不知道你有沒有覺得,這種高頻率地錄制 Snapshot、對比、再對比的方式有點兒麻煩?我需要不斷的去點擊“add date”,然后鼠標又要跑過去點擊手動 GC、錄制 Snapshot、等待錄制完畢,再去操作,再去錄制。有沒有簡單一些的方式來查找內存泄漏?這個時候我們回到 Memory 最初始的界面,你突然發現 “Heap snapshot”下面還有一個 radio:“Allocation instrumentation on timeline”,并且這個 radio 下面的介紹文案的最后寫著:“Use this profile type to isolate memory leaks”,原來這是一個專門用于調查內存泄漏的工具!于是,我們選中這個 radio,點擊開始錄制按鈕,然后將注意力放在頁面上,然后你發現當點擊“add date”按鈕時,右面錄制的 timeline 便會多出一個心跳:
圖 9 Allocation instrumentation on timeline
如圖 9 所示,每當我們點擊“add date”按鈕時,右面都有一個對應的心跳,當我們點擊“clear”按鈕時,剛才出現的所有心跳便全都“縮回”去了,于是我們得出結論:每一個“心跳”都是一次內存分配,其高度代表內存分配的量,在之后的時間推移過程中,如果剛才心跳對應的被分配的內存被 GC 回收了,“心跳”便會跟著變化為回收之后的高度。于是,我們便擺脫了在 Snapshot 中來回操作、錄制的窘境,只需要將注意力集中在頁面的操作上,并觀察哪個操作在右邊的時間線變化中是可疑的。
經過一系列操作,我們發現“add date”這個按鈕的點擊行為很可疑,因為它分配的內存不會自動被回收,也就是只要點擊一次,內存就會增長一點,我們停止錄制,得到了一個 timeline 的 Snapshot,這個時候如果我們點擊某個心跳的話:
圖 10 點擊某個心跳
熟悉的 Date x 3000 又出現了(圖 11),點擊一個 Date 對象看持有鏈,接下來便跟上文 Snapshot 的持有鏈分析一樣了:
圖 11 通過 timeline 找到泄漏點
這個方法的優點上文已經說明,可以非常直觀、方便的觀察內存隨可疑操作的分配與回收過程,可以方便的觀察每次分配的內存。它的缺點:錄制時間較長時 devtools 收集錄制結果的時間會很長,甚至有時候會卡死瀏覽器;下文會講到 detached DOM,這個工具不能比較出 detached DOM,而 heap snapshot 可以。
3 performance
devtools 中的 Performance 面版中也有一個 Memory 功能,下面看一下它如何使用。我們把 Memory 勾選上,并錄制一個 performance 結果:
圖 12 Performance 的錄制過程
在圖 12 中可以看到,在錄制的過程中我們連續點擊“add date”按鈕 10 次,然后點擊一次“clear”按鈕,然后再次點擊“add date” 10 次,得到的最終結果如圖 13 所示:
圖 13 Performance 的錄制結果
在圖 13 中我們可以得到下面的信息:
圖 14 通過 Performance 定位問題代碼
這種方法的優點:可以直觀得看到內存的總體走勢,并且同時得到所有操作過程中的函數調用棧和時間等信息。缺點:沒有具體的內存分配的細節,錄制的過程不能實時看到內存分配的過程。
1 全局
JS 采用標記清掃法去回收無法訪問的內存對象,被掛載在全局對象(在瀏覽器中即指的是 window 對象,在垃圾回收的角度上稱其為根節點,也叫 GC root)上的屬性所占用內存是不會被回收的,因為其是始終可以訪問的,這也符合“全局”的命名含義。
解決方案就是避免用全局對象存儲大量的數據。
2 閉包(closure)
我們把【代碼 1】稍加改動便可以得到一個閉包導致內存泄漏的版本:
代碼 3 閉包導致內存泄漏
將上述代碼加載到 chrome 中,并用 timeline 的方式錄制一個 Snapshot,得到的結果如圖 15 所示:
圖 15 閉包的錄制結果
我們選中 index=2 的心跳,可以看到 Constructor 里面出現了一個 "(closure)",我們展開這個 closure,可以看到里面的 "inner()",inner() 后面的 "()" 表示 inner 是一個函數,這時候你可能會問:“圖中的 Constructor 的 Retained Size 大小都差不多,為什么你要選 (closure)?”,正是因為沒有明顯占比較高的 Retained Size 我們才隨便選一個調查,后面你會發現不管你選了哪一個最后的調查鏈路都是殊途同歸的。
我們在下面的 Retainers 中看下 inner() 的持有細節:從下面的 Retainers 中可以看出 inner() 這個 closure 是某個 Array 的第 2 項(index 從 0 開始),而這個數組的持有者是 system/Context(即全局) 中的 ary,通過觀察可以看到 ary 的持有大?。≧etained Size)是 961KB 大約等于 192KB 的 5 倍,5 即是我們點擊“add date”按鈕的次數,而下面的 5 個 "previous in system/Context" 每個大小都是 192KB,而它們最終都是被某個 inner() 閉包持有,至此我們便可以得出結論:全局中有一個 ary 數組,它的主要內存是被 inner() 填充的,通過藍色的 index.html:xx 處的代碼入口定位到代碼所在地看一下一切就都了然了,原來是 inner() 閉包內部持有了一個大對象,并且所有的 inner() 閉包及其持有的大對象都被 ary 對象持有,而 ary 對象是全局的不會被回收,導致了內存泄漏(如果這種行為不符合預期的話)。返回去,如果這個時候你選擇上面提到的 system/Context 構造器,你會看到(見圖 16,熟悉吧):
圖 16 system/Context
也就是你選擇的 system/Context 其實是 inner() 閉包的上下文對象(context),而此上下文持有了 192KB 內存,通過藍色的 index.html:xx 又可以定位到問題代碼了。如果你像圖 17 一樣選擇了 Date 構造器進行查看的話也可以最終定位到問題,此處將分析過程留給讀者自己進行:
圖 17 選中 Date 構造器
3 Detached DOM
我們先看一下下面的代碼,并用 chrome 載入它:
代碼 4 Detached Dom
然后我們采用 Heap Snapshot 的方式將點擊“del”按鈕前后的兩個 snapshot 錄制下來,得到的結果如圖 6 所示。我們選用和 snapshot 1 對比的方式并在 snapshot 2 的過濾器中輸入 "detached"。我們觀察得到的篩選結果的 "Delta" 列,其中不為 0 的列如下:
要解釋上述表格需要先介紹一個知識點:DOM 對象被回收需要同時滿足兩個條件,1、DOM 在 DOM 樹中被刪掉;2、DOM 沒有被 JS 對象引用。其中第二點還是比較容易被忽視的。正如上面的例子所示,Detached HTMLButtonElement +1 代表有一個 button DOM 被從組件樹中刪掉了,但是仍有 JS 引用之(我們不考慮有意為之的情況)。
相似的,Detached EventListener 也是因為 DOM 被刪掉了,但是事件沒有解綁,于是 Detached 了,解決方案也很簡單:及時解綁事件即可。
于是解決的方法就很簡單了:參見代碼 5,回掉函數 del 在執行完畢時臨時變量會被回收,于是兩個條件就都同時滿足了,DOM 對象就會被回收掉,事件解綁了,Detached EventListener 也就沒有了。值得注意的是 table 元素,如果一個 td 元素發生了 detached,則由于其自身引用了自己所在的 table,于是整個 table 就也不會被回收了。
代碼 5 Detached DOM 的解決方法
圖 18 Detached DOM 的 Snapshot
Performance monitor 工具
DOM/event listener 泄漏在編寫輪播圖、彈窗、toast 提示這種工具的時候還是很容易出現的,chrome 的 devtools 中有一個 Performance monitor 工具可以用來幫助我們調查內存中是否有 DOM/event listener 泄漏。首先看一下代碼 6:
代碼 6 不斷增加 DOM NODE
按照我們圖 19 的方式打開 Performance monitor 面版:
圖 19 打開 Performance monitor 工具
DOM Nodes 右側的數量是當前內存中的所有 DOM 節點的數量,包括當前 document 中存在的和 detached 的以及計算過程中臨時創建的,每當我們點擊一次“add date”按鈕,并手動觸發 GC 之后 DOM Nodes 的數量就 + 2,這是因為我們向 document 中增加了一個 button 節點和一個 button 的文字節點,就像圖 20 中所示。如果你寫的 toast 組件在臨時插入到 document 并過一會兒執行了 remove 之后處于了 detached 狀態的話,Performance monitor 面版中的 DOM Nodes 數量就會不斷增加,結合 snapshot 工具你便可以定位到問題所在了。值得一提的是,有的第三方的庫的 toast 便存在這個問題,不知道你被坑過沒有。
圖 20 不斷增加的 DOM Nodes
4 console
這一點可能有人不會留意到,控制臺打印的內容是需要始終保持引用的存在的,這一點也是值得注意的,因為打印過多過大對象的話也是會造成內存泄漏的,如圖 21 所示(配合代碼 7)。解決方法便是不要肆意打印對象到控制臺中,只打印必要的信息出來。
代碼 7 console 導致內存泄漏
圖 21 console 導致的內存泄漏
本文用了幾個簡單的小例子介紹了內存泄漏出現的時機、尋找泄漏點的方法并將各種方法的優缺點進行了對比,總結了避免出現內存泄漏的注意點。希望能對讀者有所幫助。文中如果有本人理解錯誤或書寫錯誤的地方歡迎留言指正。
參考
https://commandlinefanatic.com/cgi-bin/showarticle.cgi?article=art038
https://developer.chrome.com/docs/devtools/memory-problems/
https://www.bitdegree.org/learn/chrome-memory-tab
作者 | 木及
原文鏈接:http://click.aliyun.com/m/1000287965/
本文為阿里云原創內容,未經允許不得轉載。
*請認真填寫需求信息,我們會在24小時內與您取得聯系。