這篇文章主要介紹了關於如何解決JS高程中的垃圾回收機制與常見內存洩露的問題,有著一定的參考價值,現在分享給大家,有需要的朋友可以參考一下
前言
起因是因為想了解閉包的記憶體外洩機制,然後想起《js高階程式設計》中有關於垃圾回收機制的解析,之前沒有很懂,過一年回頭再看就懂了,寫給大家分享一下。如果喜歡的話可以按波贊/關注,支持一下。
記憶體的生命週期:
分配你所需要的記憶體:
由於字串、對象等等沒有固定的大小,js程式在每次創建字串、物件的時候,程式都會分配記憶體來儲存那個實體。
使用分配到的記憶體做點什麼。
不需要時將其釋放回歸:
在不需要字串、物件的時候,需要釋放其所佔用的內存,否則將會消耗完系統中所有可用的內存,造成系統崩潰,這就是垃圾回收機制所存在的意義。
所謂的記憶體洩漏指的是:由於疏忽或錯誤造成程式未能釋放那些已經不再使用的內存,造成記憶體的浪費。
垃圾回收機制:
在C和C 之類的語言中,需要手動來管理記憶體的,這也是造成許多不必要問題的根源。幸運的是,在編寫js的過程中,記憶體的分配以及記憶體的回收完全實現了自動管理,我們不用操心這種事情。
垃圾收集機制的原理:
垃圾收集器會按照固定的時間間隔,週期性的找出不再繼續使用的變量,然後釋放其佔用的記憶體。
什麼叫不再繼續使用的變數?
不再使用的變數也就是生命週期結束的變量,是局部變量,局部變數只在函數的執行過程中存在,當函數運行結束,沒有其他引用(閉包),那麼該變數會被標記回收。
全域變數的生命週期直到瀏覽器卸載頁面才會結束,也就是說全域變數不會被當成垃圾回收。
標記清除:目前採用的垃圾收集策略
工作原理:
當變數進入環境時(例如在函數中宣告一個變數),並將這個變數標記為“進入環境”,當變數離開環境時,則標記為“離開環境”。標記「離開環境」的就回收記憶體。
工作流程:
垃圾收集器會在運行的時候會給儲存在記憶體中的所有變數都加上標記。
去掉環境中的變數以及被環境中的變數所引用的變數的標記。
那些還有標記的變數被視為準備刪除的變數。
最後一個垃圾收集器會執行最後一步記憶體清除的工作,銷毀那些帶有標記的值並回收它們所佔用的記憶體空間。
到2008年為止,IE、Chorme、Fireofx、Safari、Opera 都使用標記清除式的垃圾收集策略,只不過垃圾收集的時間間隔互有不同。
引用計數略:被廢棄的垃圾收集策略
循環引用:追蹤記錄每個值被引用的技術
在舊版的瀏覽器中(對,又是IE),IE9以下BOM和DOM物件就是使用C 以COM物件的形式實現的。
COM的垃圾收集機制採用的就是引用計數策略,這種機制在出現循環引用的時候永遠釋放不掉記憶體。
var element = document.getElementById('something'); var myObject = new Object(); myObject.element = element; // element属性指向dom element.someThing = myObject; // someThing回指myObject 出现循环引用(两个对象一直互相包含 一直存在计数)。
解決方式是,當我們不使用它們的時候,手動切割連結:
myObject.element = null; element.someThing = null;
淘汰:
IE9把BOM和DOM對象轉向了真正的js對象,避免使用這種垃圾收集策略,消除了IE9以下常見的記憶體洩漏的主要原因。
IE7以下有一個宣告狼藉的效能問題,大家了解一下:
256個變量,4096個物件(或數組)字面或64KB的字串,達到任何一個臨界值會觸發垃圾收集器運作。
如果一個js腳本的生命週期一直保有那麼多變量,垃圾收集器會一直頻繁的運行,引發嚴重的效能問題。
IE7已修復這個問題。
哪些情況會造成記憶體洩漏?
雖然有垃圾回收機制,但我們在寫程式碼的時候,有些情況還是會造成記憶體洩漏,了解這些情況,並在編寫程式的時候,注意避免,我們的程式會更具健全性。
意外的全域變數:
上文我們提到了全域變數不會被當成垃圾回收,我們在編碼中有時會出現下面這種情況:
function foo() { this.bar2 = '默认绑定this指向全局' // 全局变量=> window.bar2 bar = '全局变量'; // 没有声明变量 实际上是全局变量=>window.bar } foo();
当我们使用默认绑定,this会指向全局,this.something
也会创建一个全局变量,这一点可能很多人没有注意到。
解决方法:在函数内使用严格模式or细心一点
function foo() { "use strict"; this.bar2 = "严格模式下this指向undefined"; bar = "报错"; } foo();
当然我们也可以手动释放全局变量的内存:
window.bar = undefined delete window.bar2
被遗忘的定时器和回调函数
当不需要setInterval
或者setTimeout
时,定时器没有被clear,定时器的回调函数以及内部依赖的变量都不能被回收,造成内存泄漏。
var someResource = getData(); setInterval(function() { var node = document.getElementById('Node'); if(node) { node.innerHTML = JSON.stringify(someResource)); // 定时器也没有清除 } // node、someResource 存储了大量数据 无法回收 }, 1000);
解决方法: 在定时器完成工作的时候,手动清除定时器。
闭包:
闭包可以维持函数内局部变量,使其得不到释放,造成内存泄漏。
function bindEvent() { var obj = document.createElement("XXX"); var unused = function () { console.log(obj,'闭包内引用obj obj不会被释放'); }; // obj = null; }
解决方法:手动解除引用,obj = null
。
循环引用问题
就是IE9以下的循环引用问题,上文讲过了。
没有清理DOM元素引用:
var refA = document.getElementById('refA'); document.body.removeChild(refA); // dom删除了 console.log(refA, "refA"); // 但是还存在引用 能console出整个p 没有被回收
不信的话,可以看下这个dom。
解决办法:refA = null;
console保存大量数据在内存中。
过多的console,比如定时器的console会导致浏览器卡死。
解决:合理利用console,线上项目尽量少的使用console,当然如果你要发招聘除外。
如何避免内存泄漏:
记住一个原则:不用的东西,及时归还,毕竟你是'借的'嘛。
减少不必要的全局变量,使用严格模式避免意外创建全局变量。
在你使用完数据后,及时解除引用(闭包中的变量,dom引用,定时器清除)。
组织好你的逻辑,避免死循环等造成浏览器卡顿,崩溃的问题。
关于内存泄漏:
即使是1byte的内存,也叫内存泄漏,并不一定是导致浏览器崩溃、卡顿才能叫做内存泄漏。
一般是堆区内存泄漏,栈区不会泄漏。
基本类型的值存在内存中,被保存在栈内存中,引用类型的值是对象,保存在堆内存中。所以对象、数组之类的,才会发生内存泄漏。
使用chorme监控内存泄漏,可以看一下这篇文章
结语
了解了内存泄漏的原因以及出现的情况,那么我们在编码过程中只要多加注意,就不会发生非常严重的内存泄漏问题。
以上就是本文的全部内容,希望对大家的学习有所帮助,更多相关内容请关注PHP中文网!
相关推荐:
原生JS基于window.scrollTo()封装垂直滚动动画工具函数
以上是如何解決JS高程中的垃圾回收機制與常見記憶體外洩的問題的詳細內容。更多資訊請關注PHP中文網其他相關文章!

是的,JavaScript的引擎核心是用C語言編寫的。 1)C語言提供了高效性能和底層控制,適合JavaScript引擎的開發。 2)以V8引擎為例,其核心用C 編寫,結合了C的效率和麵向對象特性。 3)JavaScript引擎的工作原理包括解析、編譯和執行,C語言在這些過程中發揮關鍵作用。

JavaScript是現代網站的核心,因為它增強了網頁的交互性和動態性。 1)它允許在不刷新頁面的情況下改變內容,2)通過DOMAPI操作網頁,3)支持複雜的交互效果如動畫和拖放,4)優化性能和最佳實踐提高用戶體驗。

C 和JavaScript通過WebAssembly實現互操作性。 1)C 代碼編譯成WebAssembly模塊,引入到JavaScript環境中,增強計算能力。 2)在遊戲開發中,C 處理物理引擎和圖形渲染,JavaScript負責遊戲邏輯和用戶界面。

JavaScript在網站、移動應用、桌面應用和服務器端編程中均有廣泛應用。 1)在網站開發中,JavaScript與HTML、CSS一起操作DOM,實現動態效果,並支持如jQuery、React等框架。 2)通過ReactNative和Ionic,JavaScript用於開發跨平台移動應用。 3)Electron框架使JavaScript能構建桌面應用。 4)Node.js讓JavaScript在服務器端運行,支持高並發請求。

Python更適合數據科學和自動化,JavaScript更適合前端和全棧開發。 1.Python在數據科學和機器學習中表現出色,使用NumPy、Pandas等庫進行數據處理和建模。 2.Python在自動化和腳本編寫方面簡潔高效。 3.JavaScript在前端開發中不可或缺,用於構建動態網頁和單頁面應用。 4.JavaScript通過Node.js在後端開發中發揮作用,支持全棧開發。

C和C 在JavaScript引擎中扮演了至关重要的角色,主要用于实现解释器和JIT编译器。1)C 用于解析JavaScript源码并生成抽象语法树。2)C 负责生成和执行字节码。3)C 实现JIT编译器,在运行时优化和编译热点代码,显著提高JavaScript的执行效率。

JavaScript在現實世界中的應用包括前端和後端開發。 1)通過構建TODO列表應用展示前端應用,涉及DOM操作和事件處理。 2)通過Node.js和Express構建RESTfulAPI展示後端應用。

JavaScript在Web開發中的主要用途包括客戶端交互、表單驗證和異步通信。 1)通過DOM操作實現動態內容更新和用戶交互;2)在用戶提交數據前進行客戶端驗證,提高用戶體驗;3)通過AJAX技術實現與服務器的無刷新通信。


熱AI工具

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

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

Undress AI Tool
免費脫衣圖片

Clothoff.io
AI脫衣器

Video Face Swap
使用我們完全免費的人工智慧換臉工具,輕鬆在任何影片中換臉!

熱門文章

熱工具

PhpStorm Mac 版本
最新(2018.2.1 )專業的PHP整合開發工具

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

SublimeText3 Linux新版
SublimeText3 Linux最新版

mPDF
mPDF是一個PHP庫,可以從UTF-8編碼的HTML產生PDF檔案。原作者Ian Back編寫mPDF以從他的網站上「即時」輸出PDF文件,並處理不同的語言。與原始腳本如HTML2FPDF相比,它的速度較慢,並且在使用Unicode字體時產生的檔案較大,但支援CSS樣式等,並進行了大量增強。支援幾乎所有語言,包括RTL(阿拉伯語和希伯來語)和CJK(中日韓)。支援嵌套的區塊級元素(如P、DIV),

SAP NetWeaver Server Adapter for Eclipse
將Eclipse與SAP NetWeaver應用伺服器整合。