javascript有gc嗎
javascript中有GC(垃圾回收機制)。 JavaScript是使用垃圾回收機制的語言,執行環境負責在程式碼執行時管理內存,會自動將垃圾物件(沒有被引用的物件)從記憶體中銷毀。
本教學操作環境:windows7系統、javascript1.8.5版、Dell G3電腦。
JavaScript 中的垃圾回收機制(GC)
#垃圾回收相關概念
①什麼是垃圾
沒有被使用(引用)的物件就是垃圾。
② 什麼是垃圾回收
沒有被引用的物件被銷毀,記憶體被釋放,就是垃圾回收。
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 spaceTo space
- #運行
- 實際運行的只有From spaceTo 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左右
- 分区
- Old Object Space
- 字面的老生代,存放的是新生代分配过来的内存。
- Large Object Space
- 存放其他区域放不下的较大的内存,基本都超过1M
- Map Space
- 存放存储对象的映射关系
- Code Space
- 存储编译后的代码
- Old Object Space
- 回收流程
- 标记分类(三色标记)
- 未被扫描,可回收,下面简称
1类
- 扫描中,不可回收,下面简称
2类
- 扫描完成,不可回收,下面简称
3类
- 未被扫描,可回收,下面简称
- 遍历
- 采用深度优先遍历,遍历每个对象。
- 首先将非根部对象全部标记为
1类
,然后进行深度优先遍历。 - 遍历过程中将对象压入栈,这个过程中对象被标记为
2类
。 - 遍历完成对象出栈,这个对象被标记为
3类
。 - 整个过程直至栈空
- Mark-sweep
标记完成之后,将标记为
1类
的对象进行内存释放
- 标记分类(三色标记)
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高级教程】
以上是javascript有gc嗎的詳細內容。更多資訊請關注PHP中文網其他相關文章!

熱AI工具

Undresser.AI Undress
人工智慧驅動的應用程序,用於創建逼真的裸體照片

AI Clothes Remover
用於從照片中去除衣服的線上人工智慧工具。

Undress AI Tool
免費脫衣圖片

Clothoff.io
AI脫衣器

AI Hentai Generator
免費產生 AI 無盡。

熱門文章

熱工具

記事本++7.3.1
好用且免費的程式碼編輯器

SublimeText3漢化版
中文版,非常好用

禪工作室 13.0.1
強大的PHP整合開發環境

Dreamweaver CS6
視覺化網頁開發工具

SublimeText3 Mac版
神級程式碼編輯軟體(SublimeText3)

熱門話題

如何使用WebSocket和JavaScript實現線上語音辨識系統引言:隨著科技的不斷發展,語音辨識技術已成為了人工智慧領域的重要組成部分。而基於WebSocket和JavaScript實現的線上語音辨識系統,具備了低延遲、即時性和跨平台的特點,成為了廣泛應用的解決方案。本文將介紹如何使用WebSocket和JavaScript來實現線上語音辨識系

WebSocket與JavaScript:實現即時監控系統的關鍵技術引言:隨著互聯網技術的快速發展,即時監控系統在各個領域中得到了廣泛的應用。而實現即時監控的關鍵技術之一就是WebSocket與JavaScript的結合使用。本文將介紹WebSocket與JavaScript在即時監控系統中的應用,並給出程式碼範例,詳細解釋其實作原理。一、WebSocket技

如何利用JavaScript和WebSocket實現即時線上點餐系統介紹:隨著網路的普及和技術的進步,越來越多的餐廳開始提供線上點餐服務。為了實現即時線上點餐系統,我們可以利用JavaScript和WebSocket技術。 WebSocket是一種基於TCP協定的全雙工通訊協議,可實現客戶端與伺服器的即時雙向通訊。在即時線上點餐系統中,當使用者選擇菜餚並下訂單

如何使用WebSocket和JavaScript實現線上預約系統在當今數位化的時代,越來越多的業務和服務都需要提供線上預約功能。而實現一個高效、即時的線上預約系統是至關重要的。本文將介紹如何使用WebSocket和JavaScript來實作一個線上預約系統,並提供具體的程式碼範例。一、什麼是WebSocketWebSocket是一種在單一TCP連線上進行全雙工

Golang的垃圾回收(GC)一直是開發者關注的熱門話題。 Golang作為一門快速的程式語言,其自帶的垃圾回收器能夠很好地管理內存,但隨著程式規模的增大,有時會出現一些效能問題。本文將探討Golang的GC最佳化策略,並提供一些具體的程式碼範例。 Golang中的垃圾回收Golang的垃圾回收器採用的是基於並發標記-清除(concurrentmark-s

JavaScript和WebSocket:打造高效的即時天氣預報系統引言:如今,天氣預報的準確性對於日常生活以及決策制定具有重要意義。隨著技術的發展,我們可以透過即時獲取天氣數據來提供更準確可靠的天氣預報。在本文中,我們將學習如何使用JavaScript和WebSocket技術,來建立一個高效的即時天氣預報系統。本文將透過具體的程式碼範例來展示實現的過程。 We

JavaScript教學:如何取得HTTP狀態碼,需要具體程式碼範例前言:在Web開發中,經常會涉及到與伺服器進行資料互動的場景。在與伺服器進行通訊時,我們經常需要取得傳回的HTTP狀態碼來判斷操作是否成功,並根據不同的狀態碼來進行對應的處理。本篇文章將教你如何使用JavaScript來取得HTTP狀態碼,並提供一些實用的程式碼範例。使用XMLHttpRequest

用法:在JavaScript中,insertBefore()方法用於在DOM樹中插入一個新的節點。這個方法需要兩個參數:要插入的新節點和參考節點(即新節點將要插入的位置的節點)。
