您好,登錄后才能下訂單哦!
今天小編給大家分享的是javascript有垃圾回收機制gc嗎,相信很多人都不太了解,為了讓大家更加了解,所以給大家總結了以下內容,一起往下看吧。一定會有所收獲的哦。
javascript中有GC(垃圾回收機制)。JavaScript是使用垃圾回收機制的語言,執行環境負責在代碼執行時管理內存,會自動將垃圾對象(沒有被引用的對象)從內存中銷毀。
垃圾回收相關概念
① 什么是垃圾
沒有被使用(引用)的對象就是垃圾。
② 什么是垃圾回收
沒有被引用的對象被銷毀,內存被釋放,就是垃圾回收。
C、C++ 等編程語言需要手動垃圾回收。
Java、JavaScript、PHP、Python 等語言自動垃圾回收。
JS中擁有自動的垃圾回收機制,會自動將這些垃圾對象從內存中銷毀,我們不需要也不能進行垃圾回收的操作。我們需要做的只是要將不再使用的對象設置為 null 即可。
在C / C++中,跟蹤內存的使用和管理內存對開發者來說是很大的負擔
JavaScript是使用垃圾回收機制的語言,也就是說執行環境負責在代碼執行時管理內存,幫開發者卸下了這個負擔
通過自動內存管理實現內存的分配和資源的回收
基本思路很簡單,確定哪個變量不會再被使用了,把它的內存空間釋放
這個過程是周期性的,意思是這個垃圾回收程序每隔一段時間就會運行一次
像JS中的對象、字符串、對象的內存是不固定的,只有真正用到的時候才會動態分配內存
這些內存需在不使用后進行釋放以便再次使用,否則在計算機可用內存耗盡后造成崩潰
瀏覽器發展史上的垃圾回收法主要有
引用計數法
標記清除法
引用計數法
思路
變量只是對值進行引用
當變量引用該值時,引用次數+1
當該變量的引用被覆蓋或者清除時,引用次數-1
當引用次數為0時,就可以安全地釋放這塊內存。
let arr = [1, 0, 1] // [1, 0, 1]這塊內存被arr引用 引用次數為1 arr = [0, 1, 0] // [1, 0, 1]的內存引用次數為0被釋放 // [0, 1, 0]的內存被arr引用 引用次數為1 const tmp = arr // [0, 1, 0]的內存被tmp引用 引用次數為2
循環引用問題
Netscape Navigator 3.0 采用
在這個例子中,ObjectA和ObjectB的屬性分別相互引用
造成這個函數執行后,Object被引用的次數不會變成0,影響了正常的GC。
如果執行多次,將造成嚴重的內存泄漏。
而標記清除法則不會出現這個問題。
function Example(){ let ObjectA = new Object(); let ObjectB = new Object(); ObjectA.p = ObjectB; ObjectB.p = ObjectA; } Example();
解決方法:在函數結束時將其指向null
ObjectA = null; ObjectB = null;
為了解決循環引用造成的內存泄漏問題,Netscape Navigator 4.0 開始采用標記清除法
到了 2008 年,IE、Firefox、Opera、Chrome 和 Safari 都在自己的 JavaScript 實現中采用標記清理(或 其變體),只是在運行垃圾回收的頻率上有所差異。
思路
在變量進入執行上下文時打上“進入”標記
同時在變量離開執行上下文時也打上“離開”標記
從此以后,無法訪問這個變量
在下一次垃圾回收時進行內存的釋放
function Example(n){ const a = 1, b = 2, c = 3; return n * a * b * c; } // 標記Example進入執行上下文 const n = 1; // 標記n進入執行上下文 Example(n); // 標記a,b,c進入執行上下文 console.log(n); // 標記a, b, c離開執行上下文,等待垃圾回收
const和let聲明提升性能
const和let不僅有助于改善代碼風格,同時有利于垃圾回收性能的提升
const和let使JS有了塊級作用域,當塊級作用域比函數作用域更早結束時,垃圾回收程序更早介入
盡早回收該回收的內存,提升了垃圾回收的性能
V8引擎的垃圾回收
V8引擎的垃圾回收采用標記清除法與分代回收法
分為新生代和老生代
新生代
新生代垃圾回收采用
Scavenge
算法
分配給常用內存和新分配的小量內存
內存大小
32位系統16M內存
64位系統32M內存
分區
新生代內存分為以下兩區,內存各占一半
From space
To space
運行
實際運行的只有From space
To space處于空閑狀態
Scavenge
算法
解決了內存散落分塊的問題(不連續的內存空間)
相當于用空間換時間。
當From space內存使用將要達到上限時開始垃圾回收,將From space中的不可達對象都打上標記
將From space的未標記對象復制到To space。
然后清空From space、將其閑置,也就是轉變為To space,俗稱反轉。
新生代 -> 老生代
內存大小達到From space的25%
經歷了From space <-> To space的一個輪回
新生代存放的是新分配的小量內存,如果達到以下條件中的一個,將被分配至老生代
老生代
老生代采用
mark-sweep
標記清除和mark-compact
標記整理
通常存放較大的內存塊和從新生代分配過來的內存塊
內存大小
32位系統700M左右
64位系統1.4G左右
分區
存儲編譯后的代碼
存放存儲對象的映射關系
存放其他區域放不下的較大的內存,基本都超過1M
字面的老生代,存放的是新生代分配過來的內存。
Old Object Space
Large Object Space
Map Space
Code Space
回收流程
標記完成之后,將標記為1類
的對象進行內存釋放
采用深度優先遍歷,遍歷每個對象。
首先將非根部對象全部標記為1類
,然后進行深度優先遍歷。
遍歷過程中將對象壓入棧,這個過程中對象被標記為2類
。
遍歷完成對象出棧,這個對象被標記為3類
。
整個過程直至棧空
未被掃描,可回收,下面簡稱1類
掃描中,不可回收,下面簡稱2類
掃描完成,不可回收,下面簡稱3類
標記分類(三色標記)
遍歷
Mark-sweep
Mark-compact
垃圾回收完成之后,內存空間是不連續的。
這樣容易造成無法分配較大的內存空間的問題,從而觸發垃圾回收。
所以,會有Mark-compact步驟將未被回收的內存塊整理為連續地內存空間。
頻繁觸發垃圾回收會影響引擎的性能,內存空間不足時也會優先觸發Mark-compact
垃圾回收優化
增量標記
如果用集中的一段時間進行垃圾回收,新生代倒還好,老生代如果遍歷較大的對象,可能會造成卡頓。
增量標記:使垃圾回收程序和應用邏輯程序交替運行,思想類似Time Slicing
并行回收
在垃圾回收的過程中,開啟若干輔助線程,提高垃圾回收效率。
并發回收
在邏輯程序執行的過程中,開啟若干輔助線程進行垃圾回收,清理和主線程沒有任何邏輯關系的內存。
全局變量
// exm1 function Example(){ exm = 'LeBron' } // exm2 function Example(){ this.exm = 'LeBron' } Example()
未清除的定時器
const timer = setInterval(() => { //... }, 1000) // clearInterval(timer)
閉包
function debounce(fn, time) { let timeout = null; return function () { if (timeout) { clearTimeout(timeout); } timeout = setTimeout(() => { fn.apply(this, arguments); }, time); }; } const fn = debounce(handler, 1000); // fn引用了timeout
未清除的DOM元素引用
const element = { // 此處引用了DOM元素 button:document.getElementById('LeBron'), select:document.getElementById('select') } document.body.removeChild(document.getElementById('LeBron'))
這個其實不難,瀏覽器原帶的開發者工具Performance就可以
步驟
F12打開開發者工具
選擇Performance工具欄
勾選屏幕截圖和Memory
點擊開始錄制
一段時間之后結束錄制
結果
堆內存會周期性地分配和釋放
如果堆內存的min值在逐漸上升則存在內存泄漏
1、盡量不在for循環中定義函數
// exm const fn = (idx) => { return idx * 2; } function Example(){ for(let i=0;i<1000;i++){ //const fn = (idx) => { // return idx * 2; // } const res = fn(i); } }
2、盡量不在for循環中定義對象
function Example() { const obj = {}; let res = ""; for (let i = 0; i < 1000; i++) { // const obj = { // a: i, // b: i * 2, // c: i * 3, // }; obj.a = i; obj.b = i * 2; obj.c = i * 3; res += JSON.stringify(obj); } return res }
3、清空數組
arr = [0, 1, 2] arr.length = 0; // 清空了數組,數組類型不變 // arr = [] // 重新申請了一塊空數組對象內存
關于javascript有垃圾回收機制gc嗎就分享到這里了,希望以上內容可以對大家有一定的參考價值,可以學以致用。如果喜歡本篇文章,不妨把它分享出去讓更多的人看到。
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。