1. 程式人生 > >談一談Javascript記憶體釋放那點事

談一談Javascript記憶體釋放那點事

Javascript語言有自己的一套記憶體回收機制,一般情況下區域性變數和物件使用完就會被系統自動回收,無需我們理會。但是碰到閉包的情況這些變數和物件是不會被回收的,對於普通的web站點,頁面重新整理或跳轉這些記憶體也會被回收。如果是單頁web站點,頁面切換及資料請求都是通過ajax無重新整理機制實現的,頁面資源無法自動回收,時間長了會嚴重影響效能,造成記憶體洩漏甚至頁面崩潰直接退出,這時候手動釋放不用資源就非常必要了,包含刪除dom、釋放物件等,這篇文章介紹如何釋放JS物件。

一、在此之前我們需要學會使用Chrome的記憶體分析工具來檢視頁面各個物件的記憶體佔用情況

1、在開發者工具中選中Profiles,選擇Take Heap Snapshot,點選Take Snapshot按鈕


2、選中生成的Heap Snapshot報表,在右邊輸入要查詢的物件


來看看下面幾個例子【注:例子實現的功能實際意義,只是為了展示今天要講的東西】:

html部分:

<style>
        .div1,.div2 {
        width:100px;
        height:100px;
        border:1px solid red;
        }
    </style>

<div class="div1">
        div1
    </div>
    <div class="div2">
        div2
    </div>

二、沒有形成閉環,建立的物件使用完後自動銷燬或手動設為null銷燬

1、系統自動回收Test物件

window.onload=function(){

  function Test(Dom)
  {
  this.Dom=Dom;
 this.str='';
  }
  
  var div1=document.getElementsByClassName('div1')[0];
  var myTest=new Test(div1); 
  
  
 }
2、在div1上加了click事件監聽
window.onload=function(){

  function Test(Dom)
  {
  this.Dom=Dom;
 this.str='';
  this.dom.addEventListener('click', function () { }, false);
 }
  
  var div1=document.getElementsByClassName('div1')[0];
  var myTest=new Test(div1); 
  
  
 }

監聽函式中沒有對tes物件變數的引用,沒有形成閉包,故程式碼執行完後會自動銷燬


3、使用了延時執行

window.onload=function(){

  function Test(Dom)
  {
   this.Dom=Dom;
  this.str='';
   var self=this;
   var timer = window.setTimeout(function () {self.str='123';},1000)
 }
  
  var div1=document.getElementsByClassName('div1')[0];
  var myTest=new Test(div1); 
   
 }

使用了window.setTimeout延遲,執行函式中有引用物件的屬性,但引用是一次性的,沒有形成閉環

4、使用了定時器

window.onload=function(){

  function Test(Dom)
  {
   this.Dom=Dom;
  this.str='';
   var self=this;
   var timer = window.setInterval(function () {}, 1000);
 }
  
  var div1=document.getElementsByClassName('div1')[0];
  var myTest=new Test(div1); 
   
 }
迴圈執行函式中沒有對物件屬性的引用,沒有形成閉環

三、形成了閉環,系統無法自動回收物件資源,也無法手動將物件設為null銷燬,只能刪除物件屬性的引用,再通過手動將物件設定為null銷燬

1、dom的監聽事件中有對物件屬性的引用

window.onload=function(){

  function Test(Dom)
  {
  this.Dom=Dom;
 this.str='';
  this.dom.addEventListener('click', function () {self.str='123'; }, false);
 }
  
  var div1=document.getElementsByClassName('div1')[0];
  var myTest=new Test(div1); 
   
 }

為了能夠移除監聽事件,我們將監聽函式單獨定義。再Test函式增加一個原型方法Destroy,作用就是刪除dom的click監聽事件,供外部呼叫。

給div2增加一個click事件,呼叫Test的destroy方法銷燬Test物件

window.onload=function(){

  function Test(Dom)
  {
  this.Dom=Dom;
 this.str=''; 
  this.A=function(){
      this.str='123';
  }
 this.dom.addEventListener('click', self.A, false);
 }

Test.prototype.destroy = function () {
  var self=this;
  this.dom.removeEventListener('click',self.A, false);
 }
 var div1=document.getElementsByClassName('div1')[0]; var myTest=new Test(div1);

//點選div2,銷燬Test物件
 var div2Obj = document.getElementsByClassName('div2')[0];
  div2Obj.onclick = function () {             
    myTest.destroy();
    myTest = null;
   }  } 點選div2後通過記憶體分析發現Test物件消失了,說明已經銷燬了

2、window.setInterval事件中有對物件屬性的引用
window.onload=function(){

  function Test(Dom)
  {
  this.Dom=Dom;
 this.str='';
  this.dom.addEventListener('click', function () {self.str='123'; }, false);
 }
  
  var div1=document.getElementsByClassName('div1')[0];
  var myTest=new Test(div1); 
   
 }

我們增加一個物件屬性timer來接收window.setInterval的控制代碼,在destory方法中清除定時器。

window.onload=function(){

  function Test(Dom)
  {
  this.Dom=Dom;
 this.str=''; 
  this.timer=null;
 this.timer = window.setInterval(function () { self.str = '123';}, 1000);
 }

  Test.prototype.destroy = function () {
  window.clearInterval(this.timer);
 }

 var div1=document.getElementsByClassName('div1')[0];  
  var myTest=new Test(div1); 

    //點選div2,銷燬Test物件
   var div2Obj = document.getElementsByClassName('div2')[0];
   div2Obj.onclick = function () {              
    myTest.destroy();
    myTest = null;
   }   
}
點選div2後通過記憶體分析發現Test物件消失了,說明已經銷燬了

從上面的例子可以看出,想手動釋放含有閉包的物件時,必須先將引用物件屬性的事件刪除,然後設定為null方可消耗物件。這種事件一般是可以多次執行的,如原生事件的監聽,定時器。一般比較有名較完善的外掛都有帶銷燬資源方法,如iscroll外掛,裡面就有一個destroy原型方法,它裡面也就是移除事件監聽和刪除定時器。大家可以去看看原始碼。

寫在最後

單頁web的效能優化之路任重而道遠,本文只是談了一下如何釋放建立的物件,其實還有很多可以優化的點:dom優化、動畫優化等。希望可以和大家一起討論。

相關推薦

Javascript記憶體釋放

Javascript語言有自己的一套記憶體回收機制,一般情況下區域性變數和物件使用完就會被系統自動回收,無需我們理會。但是碰到閉包的情況這些變數和物件是不會被回收的,對於普通的web站點,頁面重新整理或跳轉這些記憶體也會被回收。如果是單頁web站點,頁面切換及資料請求都是通

32位,64位和記憶體

這兩天果殼上有些人問到了關於在32位系統下使用4G或以上記憶體的問題。對於“32位作業系統能否使用4G或以上的記憶體”這個問題,在網路上爭論也是很多。下面,我就我自己對作業系統記憶體分配的理解,談談我的觀點。          32位、64和“最大記憶體量”是怎麼回事   

Android記憶體

Android記憶體及其優化 或許,因為開發週期的原因;因為自身知識水平的原因;因為經驗的原因;又或者是你接了個爛攤子。我們寫出了並不太理想的程式碼,這都是可以接受的,只要你會去持續優化,這些問題都會得到改善。而有些人是心有餘而力不足,“我也想優化,可是怎麼去優化呢?”。本篇文章將給

Swift和Objective-C之間的。。。

Swift 是一種新的程式語言,用於編寫 iOS 和 OS X 應用。Swift 結合了 C 和 Objective-C 的優點並且不受C相容性的限制。Swift 採用安全的程式設計模式並添加了很多新特性,這將使程式設計更簡單,更靈活,也更有趣。Swift 是基

JavaScript面向物件

面向物件概念理解 面嚮物件語言有個標誌=>它們都具有類的概念,通過類可以建立任意多個具有相同屬性和方法的物件。 面向物件有三大特性 封裝 繼承 多型 但JS中物件與純面嚮物件語言中的物件是不同的 JS中的物件: 無序屬性的集合,其屬性可以包含基本值、

JavaScript非同步

什麼是js非同步? 我們常常聽到單執行緒、多執行緒、同步、非同步這些概念,那麼這些東西到底是什麼呢? 1.單執行緒就是隻有一個主線的執行緒,程式碼從上往下順序執行,主執行緒負責執行程式的所有程式碼(UI展現以及重新整理,網路請求,本地儲存等等) 例如:一個專案從產品

幾種處理 JavaScript 非同步操作的辦法

寫於 2017.02.26 引言 js的非同步操作,已經是一個老生常談的話題,關於這個話題的文章隨便google一下都可以看到一大堆。那麼為什麼我還要寫這篇東西呢?在最近的工作中,為了編寫一套相對比較複雜的外掛,需要處理各種各樣的非同步操作。但是為了體積和相容性,不打算引入任何的pollyfil

Javascript中setTimeout

前段時間公司在開會的時候提到了Javascript裡的setTimeout,同事們的討論很有意思,決定和大家分享一下。 話不多說,上程式碼 //程式碼塊A document.querySelector('button').onclick = function(){    

跑PHP計劃任務

amp reg dmi content set cnblogs input span put 公司所用計劃任務均是大概這樣子的: */2 * * * * root cd /opt/xxxx/test_S1/html/xxxx/admin; php index.php ta

商品編碼的問題

什麽是 開發測試 upd 無奈 是不是 默認 修改 都沒有 做了 如題:今天談一談商品編碼的問題,我們不是完全從物流和商品本身的角度去談商品該怎麽編碼才符合國際標準,EAN,UPC啥啥啥怎麽樣的。我們從計算機程序設計,電商,數據庫存儲的角度看一看商品編碼,首先商品有哪些編碼

APP版本號問題

nbsp param pos 得到 大於 reat 兼容 pat 用戶 如題:談一談APP版本號問題 為什麽要談這個問題,周五晚上11~12點,被微信點名,說APP有錯,無效的版本號,商城無法下單。我正在準備收拾東西,周末回老家,結果看到這樣問題,菊花一緊。我擦,我剛加的

購物車

關系 大數據 tor 存儲 緩存 不同的 影響 什麽 activity 如題:今天談一談購物車這個話題。最近在重構購物車,所以借著興頭談一談購物車的設計。很久很久以前,那個時候還有沒有智能手機,還沒有京東,淘寶也剛剛起步,大概是在上學時讀書看到的,記得書中說購物車是放在se

,你對軟件測試行業的了解

可能 之前 測試執行 軟件設計 補丁 穩定 tro 人員 開發 1、提高軟件的質量:軟件穩定,軟件達到客戶的需求2、軟件測試的目的:發現軟件缺陷,提高軟件質量,發現盡可能多的問題,各種場景各種情況下是否有問題3、微軟這個牛逼的公司,wingdow要升級,軟件要打補丁。測試時

原生JS中的【面向對象思想】

時間 lin 因此 pre defined 成員方法 .... 面向對象的思想 其實在 【重點提前說:面向對象的思想很重要!】 最近開始接觸學習後臺的PHP語言,在接觸到PHP中的面向對象相關思想之後,突然想到之前曾接觸的JS中的面向對象思想

MPU6050 姿態融合(轉)

nat 不同 四軸飛行器 物體 b- float 例子 只需要 原理 姿態角(Euler角)pitch yaw roll飛行器的姿態角並不是指哪個角度,是三個角度的統稱。它們是:俯仰、滾轉、偏航。你可以想象是飛機圍繞XYZ三個軸分別轉動形成的夾角。地面坐標系(earth-s

OMO的創新之路

創新首先,中國是唯一迎來OMO時代的國家,是移動支付最早普及和最大規模的國家。從線上線下的流量將雙向交織。O2O模式是單向的從線上到線下,OMO模式下,是線上與線下將雙向交織,互相導流。需要強調的是,中國是第一個,可能也是很長一段時間內唯一一個能夠把線上線下打通的國家。起關鍵作用的是移動支付的普及。移動支付是

Dijkstra

highlight wid eight tex targe AS tdi CP ems dijkstra呢是最短路三大算法之一。很多人都覺得不如spfa,但是這兩者在跑稠密圖時,dijkstra有奇效 在講之前先說一說食用方法: 適用於有向的無負權值的圖。 樣例

前後端分離開發

前端 後端 開發 大家好,初來乍到,有點小緊張,寫得不好的請各位大佬多多批評指正。 我老板是個不懂技術的 boss,前天他找我去負責一個新項目,我內心一想,勞資早受夠了這些老古董項目的苦了,這次肯定要按我想法來搞了,開心。這裏說一下,我是寫Java的,之前一直在公司一直是維護別人寫的項目,祖傳代碼

你對js線程的理解

傳遞參數 改變 AS PE javascrip 瀏覽器 執行順序 主線程 任務 js線程:javascript是單線程的,所有任務都需要排隊,這些任務分為同步任務和異步任務,單線程上有一個主線程任務。同步任務必須再主線程上排隊進行,而異步任務(類似於點擊事件)必須在主線程上

Android8.0適配

懸浮 新增功能 nta onstop config ges 保持 com dfa 1、通知渠道(Channeld) 當然,適配8.0的第一步自然是把targeSdk升級到26,在8.0中所有通知的實現都需要提供通知渠道,否則,所有通知在8.0系統上面都不能正常顯示; 下圖是