標籤: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 記憶體泄露