无码人妻精一区二区三区,eeuss影院www在线观看,无码精品久久久久久人妻中字,日韩av高清在线看片

推薦新聞
實(shí)戰(zhàn)Hybird app:內(nèi)存溢出與優(yōu)化
發(fā)布者:深藍(lán)互聯(lián)
發(fā)布時間:2019-08-29
點(diǎn)擊:次

關(guān)于性能:

首先我不得不承認(rèn)一個事實(shí),移動端的性能跟PC端,那完全不是一回事

比如用innerHTML繪制大段的HTML結(jié)構(gòu),之后同步獲取生成HTML中的ID節(jié)點(diǎn),結(jié)果不存在

這種問題在單頁面模擬多頁面,動態(tài)創(chuàng)建DOM的時候,尤為明顯

var element   = $('<div id = "aaron">...填充大量結(jié)構(gòu)...</div>');

$(root).html(element)

$('#aaron')  //為空
  • 這個是很簡單的一段代碼,按照常規(guī)的認(rèn)識,JS主線程與GUI的渲染線程是互斥的,所以在執(zhí)行JS的時候,GUI應(yīng)該就是掛起的, 同理執(zhí)行GUI的時候亦然, 因?yàn)镴S可以動態(tài)操作節(jié)點(diǎn),所以如果我們在GUI繪制的時候做操作明顯就會打亂了,所以互斥的解釋也合理
  • 但是實(shí)際上這樣并不能直接獲取到$('#aaron'),PC上基本不會出現(xiàn),常規(guī)的辦法都是加setTimeout
  • 實(shí)際上由于setTimeout的機(jī)制,所以也是不準(zhǔn)確的,當(dāng)然我已經(jīng)有一個比較完美的方式解決

 


關(guān)于JavaScript內(nèi)存管理:

原文:https://developer.mozilla.org/en-US/docs/Web/JavaScript/Memory_Management

JavaScript會給開發(fā)者一個錯覺:可以不用考慮內(nèi)存管理

現(xiàn)代瀏覽器已經(jīng)夠聰明了,從2012年起,所有現(xiàn)代瀏覽器都使用了標(biāo)記-清除垃圾回收算法。所有對JavaScript垃圾回收算法的改進(jìn)都是基于標(biāo)記-清除算法的改進(jìn),并沒有改進(jìn)標(biāo)記-清除算法本身和它對“對象是否不再需要”的簡化定義。

所以引用計數(shù)收集與循環(huán)引用之類的都不再是問題了,過去導(dǎo)致內(nèi)存泄漏的許多經(jīng)典模式在現(xiàn)代瀏覽器中以不再導(dǎo)致泄漏內(nèi)存。

但是,如今有一種不同的趨勢影響著內(nèi)存泄漏。許多人正設(shè)計用于在沒有硬頁面刷新的單頁中運(yùn)行的 Web 應(yīng)用程序。在那樣的單頁中,從應(yīng)用程序的一個狀態(tài)到另一個狀態(tài)時,很容易保留不再需要或不相關(guān)的內(nèi)存。

典型的就是: 單頁面模擬多頁面的行為

 


簡單的內(nèi)存管理測試

視圖:

image

HTML結(jié)構(gòu):

<button id="start_button">Start</button>
<button id="destroy_button">Destroy</button>

腳本代碼:

 
var Leaker = function() {
    this.name = 'aaron'
};

$("#start_button").click(function(){
 leak = new Leaker();
});

$("#destroy_button").click(function(){
  leak = null;
});
 

點(diǎn)擊Start  產(chǎn)生一個對象leak = new Leaker();

點(diǎn)擊Destroy 銷毀這個對象 觀察下內(nèi)存中變化(工具后面會提到)

點(diǎn)擊Start ,產(chǎn)生一個對象

image

 

點(diǎn)擊Destroy,對象銷毀

image

那么這個圖很形象的說明了,#Delata釋放了一個實(shí)例,就是內(nèi)存被回收了

如果不做任何處理,那么這個對象leak始終最存在整個生命周期內(nèi)(全局上下文的情況)

如果leak = null,內(nèi)存確實(shí)是由瀏覽器GC 自動給回收了

 

閉包引起的內(nèi)存泄漏:

代碼:內(nèi)部增加了一個定時器,遞歸調(diào)用

 
var count = 0;

var Leaker = function(){};

Leaker.prototype = {
    init:function(){
        this._interval = null;
        this.start();
    },

    start: function(){
        var self = this; //遞歸調(diào)用自身
        this._interval = setInterval(function(){
            self.onInterval();
        }, 100);
    },

    destroy: function(){
        if(this._interval !== null){
            clearInterval(this._interval);
        }
    },

    onInterval: function(){
        count++;
        console.log("Interval",count);
    }
};
 

 

從樣的觀察

我在按了銷毀,leak = null了

可見代碼依然還在走,可見此時內(nèi)存絕對的溢出了,也就是失控了

image

 

但是監(jiān)視器顯示該對象回收了

image

那么這個問題就很明顯了,通過leak = null 銷毀的只是引用,內(nèi)部如果還存在引用的話,這個heap是不會被回收的

此時這個內(nèi)存我們已經(jīng)管理不到了,會一直遞歸下去

要解決只能在銷毀的時候先停止定時器了

 

由此可見,引用不僅僅只是外部的, 內(nèi)部同樣存在這樣的問題,當(dāng)然引用類型的機(jī)制本來就是這樣的

 

所以在日常的代碼編寫方面,JS的坑確實(shí)不少,接下來看看我項(xiàng)目中的大坑吧!??!


 

應(yīng)用截圖:

9_T`B{QZZKGCVJHU@0E[]S2image

 

內(nèi)存使用檢測:

Eclipse

image

 

Eclipse不熟悉的路過,我們還是回到前端的角度去處理

使用Chrome DevTools的Timeline和Profiles提高Web應(yīng)用程序的性能

 

具體的使用就不介紹了,大家接著看

抓怕的heap快照,實(shí)時反饋的信息

系統(tǒng)的閉包數(shù)

image

 

加上JQuery

image

 

項(xiàng)目中的

image

 

視圖解釋

列字段解釋:

Constructor -- 構(gòu)造器

Distance -- 估計是對象到根的引用層級距離

Objects Count -- 給出了當(dāng)前有多少個該類的對象

Shallow Size -- 對象所占內(nèi)存(不包含內(nèi)部引用的其它對象所占的內(nèi)存)(單位:字節(jié))

Retained Size -- 對象所占總內(nèi)存(包含內(nèi)部引用的其它對象所占的內(nèi)存)(單位:字節(jié))

 

小伙伴都嚇呆了

項(xiàng)目中除去系統(tǒng)與一些插件的,至少有上千個閉包

 

分析堆快照

image

Object's retaining tree視圖顯示出了該對象被哪些對象引用了,以及這個引用的名稱

 

關(guān)于XUTUTIL.Event類

XUTUTIL.Event是一個構(gòu)函數(shù)函數(shù),主要就是一個訂閱/發(fā)布模式

那么這個圖我的理解就是通過XUTUTIL構(gòu)造生成的的對象都應(yīng)該是放到這個里面,所以

根據(jù)分析圖顯示,這個類有208個對象,被實(shí)例了208次,也就是說存在這么多訂閱者了

XUTUTIL部分源碼(觀察者模式)

XUTUTIL.Event

如圖me.events[eventName]標(biāo)記,是數(shù)組保存了觀察對象了

 

 

 

點(diǎn)擊圖中的黑色實(shí)心圓圈按鈕,即可得到第二個內(nèi)存快照:

點(diǎn)擊圖中的“Summary”,可彈出一個列表,選擇“Comparison”選項(xiàng),然后選擇對比第一個,結(jié)果如下圖:

image

這個視圖列出了當(dāng)前視圖與上一個視圖的對象差異。

列名字段解釋:

# New -- 新建了多少個對象

# Deleted -- 回收了多少個對象

# Delta -- 對象變化值,即新建的對象個數(shù)減去回收了的對象個數(shù)

ALLOC -- 變化的內(nèi)存大小(字節(jié))注意Delta字段,尤其是值大于0的對象

 

很明顯翻一頁就創(chuàng)建大量的觀察對象

image

*注:因?yàn)槭菃雾撁鎽?yīng)用,動態(tài)多頁面的翻頁算法,比如當(dāng)前是從第2頁到第3頁,其實(shí)是預(yù)先創(chuàng)建第4頁面,銷毀第1頁,保留234頁,所以這個+14,不是這樣算的

 

但是第一個很明顯的問題就出來,為什么要動態(tài)創(chuàng)建這么多的觀察對象,找到代碼來源

image

 

找到問題了

注冊了大量的觀察者模式

image

 

銷毀的代碼,沒有處理注銷觀察者事件

image

 

啪啪啪啪。。。。一陣修改之后

翻頁的時候不處理了

image

 

在進(jìn)入頁面初始化的時候208變成18個了。。。在看看內(nèi)存占用。。。45016---3240

PC上的消耗,在移動端就會被放大的,所以不要放過過任何一個可優(yōu)化的地方

修改前

image

修改后

image

因?yàn)檫@個案例比較明顯,還有的問題,要靠自己慢慢去分析引用情況了

 

那么很明顯了:觀察者模式引起的內(nèi)存泄漏

需要觀察者模式(Observer)來解藕一些模塊,但如果使用不當(dāng),也會帶來內(nèi)存泄漏的問題。

排查這類型的內(nèi)存泄漏問題,主要重點(diǎn)關(guān)注被引用的對象類型是閉包(closure)和數(shù)組Array的對象。

1.如果能避免觀察模式的使用,就盡量避免,

2.避免不了一定要記得清理

 


總結(jié)出以下幾種常見的情況:

1.閉包上下文綁定后沒有釋放;

2.觀察者模式在添加通知后,沒有及時清理掉;

3.定時器的處理函數(shù)沒有及時釋放,沒有調(diào)用clearInterval方法;

4.視圖層有些控件重復(fù)添加,沒有移除。

 

 

關(guān)注深藍(lán)互聯(lián)公眾號
Copyright ? 2013-2025 深藍(lán)互聯(lián) 版權(quán)所有
友情鏈接: