日韩欧美国产精品免费一二-日韩欧美国产精品亚洲二区-日韩欧美国产精品专区-日韩欧美国产另-日韩欧美国产免费看-日韩欧美国产免费看清风阁

LOGO OA教程 ERP教程 模切知識交流 PMS教程 CRM教程 開發文檔 其他文檔  
 
網站管理員

JavaScript這幾種內存泄露寫法,你要小心了

freeflydom
2025年4月14日 9:55 本文熱度 172

今天我想和你聊聊,前端開發過程中內存泄露的問題。相信你在工作當中遇到過這樣的情況,比如,相同的代碼在開發環境運行得好好的,到線上運行一段時間后就出現頁面運行卡頓,比較嚴重時,無用的內存會持續遞增,從而導致整個系統卡頓,甚至崩潰。那么,這大概率是發生了內存泄漏。

那么,你可以思考幾個問題:

  • 什么是內存泄漏?
  • 為什么會有內存泄漏?
  • 你的哪些寫法可能會出現內存泄漏?

好,帶著這三個問題,我們來學習今天的內容。

什么是內存泄漏?

首先什么是內存泄漏呢?是放在內存中的變量憑空消失了嗎?其實并不是,而是不再使用的內存沒有得到釋放,導致內存一直在增加。我打個簡單的比方:你跟別人要東西,你不停地要,不停地要,當你不需要這些東西的時候你也不還給別人,這就是內存泄漏。

那為什么會出現內存泄漏呢,如果你了解內存的生命周期,一定會知道是哪個環節導致了內存泄漏。不管什么程序語言,它的生命周期一般可以按順序分為三個部分:

我們先來簡單了解下這三個部分都做了什么事情:第一部分是內存分配,當我們創建一個函數或者變量時,必須為它分配一定數量的內存;第二部分是內存的使用,對分配的內存進行讀和寫操作;第三部分是內存釋放階段,將不需要的內存進行釋放。

所有語言的第二部分都是明確的。第一和第三部分在 C 或者 C++ 這類底層語言中是明確的,但在像 JavaScript 這些高級語言中,大部分都是隱含的。JavaScript 是在創建變量時自動進行了分配內存,并且在不使用它們時“自動”釋放,釋放的過程稱為垃圾回收。

問題就出現在這個“自動”的垃圾回收,讓前端開發者錯誤地以為他們可以不關心內存管理。但是實際上瀏覽器 V8 引擎的垃圾回收只能解決一般問題,它自身有一些局限性。

如果你了解標記 - 清除垃圾回收算法,就會知道,它是首先從根開始將可能被引用的對象用遞歸的方式進行標記,然后將沒有標記到的對象作為垃圾進行回收。

這個算法假定設置一個叫做根的對象,在 JavaScript 里,根就是是全局對象 window。垃圾回收器將定期從全局對象 window 開始,找所有從 window 開始引用的對象,然后找這些對象引用的對象……遞歸完成后,垃圾回收器將找到所有“可獲得”的對象和收集所有“不能獲得”的對象,最后將不可獲得的對象進行回收。

但是垃圾回收機制會有這樣一個問題:假如有一些對象我們已經不需要使用了,但是仍然能被訪問到,我們沒有對它進行手動清除,那么瀏覽器引擎的就不會對這個對象回收,當無用的對象越來越多,就會導致內存泄漏。那么哪些寫法會導致內存泄漏呢?我總結了 JavaScript 中四類常見的內存泄漏寫法和避免方法,給你參考。

哪些寫法會導致內存泄漏?

1.未聲明/意外的全局變量

第一種,未聲明或者意外的全局變量。全局變量的生命周期最長,直到頁面關閉前,它都存活著,所以全局變量上的內存一直都不會被回收。所以當我們寫代碼的時候如果全局變量使用不當,沒有及時回收,或者拼寫錯誤將某個變量掛載到全局變量時,就會發生內存泄漏了。

var a = '這是一個全局變量';
function test(){
    b = '變量b'; //b 成為一個全局變量,不會被回收
}

這段代碼中,test 函數中定義了一個變量 b,沒有使用 var 或者 let 變量進行聲明,這時 b 會成為全局變量,test 執行后變量 b 不會被回收。解決方式也比較簡單,在 JavaScript 文件中添加'use strict',開啟嚴格模式,這個時候就不能使用 b 這個意外的全局變量了,開發時就會在瀏覽器控制臺報錯,避免這種情況發生。

var a = '這是一個全局變量';
function test(){
    b = '變量b'; //b 成為一個全局變量,不會被回收
}

2.遺忘的定時器

第二類常見的內存泄漏是定時器 setTimeout 和 setInterval,它的生命周期是由瀏覽器專門的線程來維護的,所以當在某個頁面使用了定時器,并且這個頁面銷毀時,如果你沒有手動去釋放清理這些定時器,那么這些定時器還是存活著的。

來看一個示例,這段代碼通過定時器注冊了一個回調函數,該回調函數內又持有當前頁面 ID 為 Node 的 DOM 元素。當頁面銷毀之后,由于定時器持有該頁面部分引用而造成定時器沒有被回收,進而導致定時器內部的數據 someData 也無法被回收,就導致了內存泄漏。

var someData = getData();
setInterval(function() {
    var node = document.getElementById('Node');
    if(node) {
        node.innerHTML = JSON.stringify(someData));
    }
}, 1000);

解決辦法是,在不使用定時器的時候將定時器取消,setInterval 設置一個 ID,然后就可以通過 clearInterval(id) 進行取消了。

var someData = getData();
var intervalId = setInterval(function() {
    var node = document.getElementById('Node');
    if(node) {
        node.innerHTML = JSON.stringify(someData));
    }
}, 1000);
// 在不使用的時候進行清除
clearInterval(intervalId)

3.事件綁定

第三種由“事件綁定”導致的內存泄漏也非常常見,一般是由于事件響應函數沒有及時移除,導致重復綁定或者 DOM 元素已經移除后未處理事件響應函數造成的,例如這段 React 代碼:

class Demo extends React.Component {
  componentDidMount() {
    window.addEventListener('resize', function() {
      // do something
    });
  }
  render() {
    return <div>test component</div>;
  }
}

組件在掛載的時候監聽了 resize 事件,但是在組件移除的時候沒有處理相應函數,假如 的掛載和移除非常頻繁,那么就會在 window 上綁定很多無用的事件監聽函數,最終導致內存泄漏。

那怎么解決呢?我們可以通過在組件卸載 componentWillUmout 的時候移除監聽事件來避免這個問題:

class Demo extends React.Component {
  componentDidMount() {
    window.addEventListener('resize', this.handleResize);
  }
  componentWillUnmount() {
    window.removeEventListener('resize', this.handleResize);
  }
  handleResize() {
    // handle resize
  }
  render() {
    return <div>test component</div>;
  }
}

4.閉包

最后一類比較重要,也是我們在開發過程中經常使用到的,那就是閉包。這里先聲明:閉包本身沒有錯,不會引起內存泄漏,而是我們使用錯誤導致的。

我們都知道,閉包有兩個主要作用,一是延伸變量作用域范圍,讀取函數內部的變量。二是讓這些變量的值始終保持在內存中。簡單理解就是,一個作用域可以訪問另外一個函數內部的局部變量。

那么,為什么會說閉包可能會導致內存泄漏呢?函數本身會持有它定義時所在的詞法環境的引用,但通常情況下,使用完函數后,該函數所申請的內存都會被回收了。但當函數內再返回一個函數時,由于返回的函數持有外部函數的詞法環境,而返回的函數又被其他生命周期東西所持有,導致外部函數雖然執行完了,但內存卻無法被回收。

我們舉個例子來看一下閉包,這個例子中函數 f1 里面返回了一個函數 f2,f2 中使用了 f1 函數中的變量 n,這樣就形成了閉包。你可以想一下 console.log 的內容應該是什么?好,答案是在執行完 f1 函數后,第一次調用 result 結果返回 1000,第二次調用結果返回了 1001。這說明了什么呢?說明變量 n 在函數執行完并沒有被銷毀,而是繼續留在了內存中。

function f1() {
  var n = 999;
  // 一個閉包
  function f2() {
    n++; // f2 作為內部函數,有權訪問父級函數作用域 f1 中的變量
    console.log(n);
  }
  return f2;
}
var result = f1();
result(); // 1000
result(); // 1001

正常來說,閉包并不是內存泄漏,因為這種持有外部函數詞法環境本就是閉包的特性,就是為了讓這塊內存不被回收,因為可能在未來還需要用到,但這無疑會造成內存的消耗,所以,我們不應該濫用閉包。

總結

今天的分享到這里就結束了,最后我們來回顧一下今天講的內容。內存泄漏發生在 JavaScript 內存自動回收階段,瀏覽器引擎在“自動”回收階段使用的是標記清除算法,可以將“不可獲得”的對象進行回收,如果我們編寫代碼的時候對一些全局變量處理不當,定時器和事件綁定沒有及時清除,或者閉包使用不當,就會引起內存泄漏問題。所以為了避免內存泄漏,最重要對一點就是養成良好對編程習慣,比如內存分配后,一定要注意寫好內存釋放的代碼,有借有還,才能高效運轉,再借不難。

?轉自https://juejin.cn/post/7490856819004620836


該文章在 2025/4/14 9:56:00 編輯過
關鍵字查詢
相關文章
正在查詢...
點晴ERP是一款針對中小制造業的專業生產管理軟件系統,系統成熟度和易用性得到了國內大量中小企業的青睞。
點晴PMS碼頭管理系統主要針對港口碼頭集裝箱與散貨日常運作、調度、堆場、車隊、財務費用、相關報表等業務管理,結合碼頭的業務特點,圍繞調度、堆場作業而開發的。集技術的先進性、管理的有效性于一體,是物流碼頭及其他港口類企業的高效ERP管理信息系統。
點晴WMS倉儲管理系統提供了貨物產品管理,銷售管理,采購管理,倉儲管理,倉庫管理,保質期管理,貨位管理,庫位管理,生產管理,WMS管理系統,標簽打印,條形碼,二維碼管理,批號管理軟件。
點晴免費OA是一款軟件和通用服務都免費,不限功能、不限時間、不限用戶的免費OA協同辦公管理系統。
Copyright 2010-2025 ClickSun All Rights Reserved

主站蜘蛛池模板: 尤物精品视频一区二区三区 | 黑人巨大精品欧美一区二区免费 | 在线视频一区二区不卡 | 国产亚洲欧美一区二区不卡 | 欧美丰满熟 | 免费精品99久 | 精品免费看一区二区三区 | 一二三四视频中文成人 | 日韩精品一区二区三区高清 | 亚洲精品a∨在线国自产拍 露脸对白不带套在线播放 亚洲一级大片 | 一二三四影视在线看片免费 | 亚洲第一天堂m | 日本黄页免费大片在线观看 | 亚洲精品中文字幕不卡 | 星空影院 | 精品一区二区三区国产视频 | 87国产私拍福利精品视频 | 扒开腿挺进肉嫩小泬喷水网站 | 精品三级一区二区三区四区 | 亚洲欧美精品中文字幕 | 国产高清片 | 亚洲高清 | 中文欧美亚洲日 | 免费国产 | 日韩电影免费观 | 丰满岳乱妇 | 在线观看精品自拍视频 | 男人操女人网站 | 日本高清视频网站www | 国产一级特黄a大片免费 | 亚洲成aⅴ人的天堂在线观看女人 | 欧美国产激情一区二区三区蜜月 | 午夜福利在线观看国产精品 | 欧美在线激情视频 | 99高清国产自产拍 | 欧美a级片一区二区在线播放 | 国产永久在线观看 | 国产亚洲一区二区手机在线观 | 姑娘色综合一二三区 | 野花香视频在线观看免费高清版 | 日本中文字幕在线视频一区 |