常見的 JavaScript 記憶體泄露

來源:互聯網
上載者:User

標籤:strong   閉包   變數   char   settime   query   函數   key   time   

記憶體流失:由於疏忽或錯誤造成程式未能釋放已經不再使用的記憶體。記憶體流失並非指記憶體在物理上的消失,而是應用程式分配某段記憶體後,由於設計錯誤,導致在釋放該段記憶體之前就失去了對該段記憶體的控制,從而造成了記憶體的浪費。1、意外的全域變數

js對未聲明變數會在全域最高對象上建立它的引用,(是以屬性存在的,而不是變數),如果在遊覽器上就是window對象,如果在node環境下就是global;如果未聲明的變數緩衝大量的資料,它可能只有在頁面被重新整理或者被關閉的時候才會釋放記憶體,這樣就造成了記憶體意外泄漏。如下例子:

function my() {    name="my name is tokey"}my()console.log(window)

在控制台可以看到

還有通過this建立意外的全域變數

function my() {    this.name="my name is tokey"}my()console.log(window.name)  //my name is tokey 此時的this指向的並不是undefined而是全域對象window

針對上面類型的記憶體流失我們在平時一定要聲明變數,不要有全域直接引用。(在JavaScript檔案中添加 ‘use strict‘,開啟strict 模式,可以有效地避免上述問題。)

2、console.log

作為前端平時使用console.log在控制台打出相對應的資訊可以說是非常常見。但如果沒有去掉console.log可能會存在記憶體流失。因為在代碼運行之後需要在開發工具能查看對象資訊,所以傳遞給console.log的對象是不能被記憶體回收。

3、閉包

首先閉包是一個函數A返回一個內聯的函數B,及時A函數執行完函數B也可以訪問函數A裡面的變數,這就是一個簡單的閉包。本質上閉包是將函數內部和外部串連起來的一座橋樑。

function my(name) {    function sendName() {        console.log(name)    }    return sendName}var test=my("tokey")test()  //tokey

在my()內部建立的sendName()函數是不會被回收的,因為它被全域變數test引用,處於隨時被調用的狀態。如果向釋放記憶體可以設定test=null;由於閉包會攜帶包含它的函數的範圍,因此會比其他函數佔用更多的記憶體。過度使用閉包可能會導致記憶體佔用過多。

4、DOM泄漏

遊覽器中DOM和js採用的是不一樣的引擎,DOM採用的是渲染引擎,而js採用的是v8引擎,所以在用js操作DOM時會比較耗費效能,因為他們需要橋來連結他們。為了減少DOM的操作,我們一般將常用的DOM。我們會採用變數引用的方式會將其緩衝在當前環境。如果在進行一些刪除、更新操作之後,可能會忘記釋放已經緩衝的DOM,話不多說直接來個例子

<!DOCTYPE html><html lang="en"><head>    <meta charset="UTF-8">    <meta name="viewport" content="maximum-scale=1.0,minimum-scale=1.0,user-scalable=0,initial-scale=1.0, width=device-width">    <title>Title</title>    <style>        *{            margin: 0;            padding: 0;        }    </style></head><body><div class="main">    <div class="test">天</div>    <div class="item">天</div>    <div class="item">向</div></div><button id="add">點擊我增加</button><button id="remove">點擊我減少</button></body><script src="js/Zepto.js"></script><script src="http://apps.bdimg.com/libs/jquery/2.1.4/jquery.min.js"></script><script>var add=document.querySelector("#add");var remove=document.querySelector("#remove");var main=document.querySelector(".main")var test=document.querySelector(".test")add.onclick=function () {    var itemN=document.createElement(‘div‘)    var txt=document.createTextNode(‘上‘)    itemN.appendChild(txt)    main.appendChild(itemN)}remove.onclick=function () {    main.removeChild(test)}</script></html>

通過chrome遊覽器的記憶體調試工作我們可以看到

在我點擊了三次增加之後,可以明顯的看到節點(綠線)有三次明顯的增加,之後我又刪除了一個節點,但綠線沒有下降,這是為什麼呢?,這也就是記憶體流失。原因就是刪除的DOM在js中有全域的引用。也就是我刪除的test在文中被引用,所以無法釋放記憶體。所以在刪除更新等操作後應該將其設定為null。

5、被遺忘的timers

js中常用的定時器setInterval()、setTimeout().他們都是規定延遲一定的時間執行某個代碼,而其中setInterval()和鏈式setTimeout()在使用完之後如果沒有手動關閉,會一直存在執行佔用記憶體,所以在不用的時候我們可以通過clearInterval()、clearTimeout() 來關閉其對應的定時器,釋放記憶體。熟悉朋友都知道這類定時器是有誤差的,所以遊覽器給出了專門的API-requestAnimationFrame();大家可以試一下。

常見的 JavaScript 記憶體泄露

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.