亚洲视频二区_亚洲欧洲日本天天堂在线观看_日韩一区二区在线观看_中文字幕不卡一区

公告:魔扣目錄網(wǎng)為廣大站長提供免費(fèi)收錄網(wǎng)站服務(wù),提交前請做好本站友鏈:【 網(wǎng)站目錄:http://www.430618.com 】, 免友鏈快審服務(wù)(50元/站),

點(diǎn)擊這里在線咨詢客服
新站提交
  • 網(wǎng)站:51998
  • 待審:31
  • 小程序:12
  • 文章:1030137
  • 會員:747

作者 | 葡萄城技術(shù)團(tuán)隊

原文鏈接:https://my.oschina.NET/powertoolsteam/blog/10122640

前言

過去,我們?yōu)g覽靜態(tài)網(wǎng)站時無須過多關(guān)注內(nèi)存管理,因?yàn)榧虞d新頁面時,之前的頁面信息會從內(nèi)存中刪除。然而,隨著單頁 Web 應(yīng)用(SPA)的興起,應(yīng)用程序消耗的內(nèi)存越來越多,這不僅會降低瀏覽器性能,甚至?xí)?dǎo)致瀏覽器卡死。因此,在編碼實(shí)踐中,開發(fā)人員需要更加關(guān)注與內(nèi)存相關(guān)的內(nèi)容。因此,小編今天將為大家介紹 JAVA 內(nèi)存泄漏的編程模式,并提供一些內(nèi)存管理的改進(jìn)方法。

什么是內(nèi)存泄漏以及如何發(fā)現(xiàn)它?

如何避免JavaScript中的內(nèi)存泄漏?

什么是內(nèi)存泄漏?

Java 對象被保存在瀏覽器內(nèi)存的堆中,并通過引用方式訪問。值得一提的是,Java 垃圾回收器則運(yùn)行于后臺,并通過識別無法訪問的對象來釋放并恢復(fù)底層存儲空間,從而保證 Java 引擎的良好運(yùn)行狀態(tài)。

當(dāng)內(nèi)存中的對象在垃圾回收周期中應(yīng)該被清理時,若它們被另一個仍然存在于內(nèi)存中的對象通過一個意外的引用所持有,就會引發(fā)內(nèi)存泄漏問題。這種情況下,冗余對象會繼續(xù)占據(jù)內(nèi)存空間,導(dǎo)致應(yīng)用程序消耗過多的內(nèi)存資源,并可能導(dǎo)致性能下降和表現(xiàn)不佳的情況出現(xiàn)。因此,及時清理無用對象并釋放內(nèi)存資源是至關(guān)重要的,以確保應(yīng)用程序的正常運(yùn)行和良好的性能表現(xiàn)。

如何發(fā)現(xiàn)內(nèi)存泄漏?

那么如何知道代碼中是否存在內(nèi)存泄漏?內(nèi)存泄漏往往隱蔽且很難檢測和定位。即使代碼中存在內(nèi)存泄漏,瀏覽器在運(yùn)行時也不會返回任何錯誤。如果注意到頁面的性能逐漸下降,可以使用瀏覽器內(nèi)置的工具來確定是否存在內(nèi)存泄漏以及是哪個對象引起的。

任務(wù)管理器(不要與操作系統(tǒng)的任務(wù)管理器混淆)提供了瀏覽器中所有選項卡和進(jìn)程的概覽。Chrome 中,可以通過在 linux 和 windows 操作系統(tǒng)上按 Shift+Esc 來打開任務(wù)管理器;而在 Firefox 中,通過在地址欄中鍵入 about:performance 則可以訪問內(nèi)置的管理器,它可以顯示每個標(biāo)簽的 Java 內(nèi)存占用情況。如果網(wǎng)站停留在那里什么都不做,但 Java 內(nèi)存使用量逐漸增加,那很可能是存在內(nèi)存泄漏。

如何避免JavaScript中的內(nèi)存泄漏?

開發(fā)者工具提供了一些先進(jìn)的內(nèi)存管理方法,例如,使用 Chrome 瀏覽器的性能記錄工具,可以對頁面的性能進(jìn)行可視化分析。在這個過程中,可以通過一些指標(biāo)來判斷是否存在內(nèi)存泄漏問題,比如堆內(nèi)存使用量增加的情況,并及時采取措施解決這些問題,以確保應(yīng)用程序的正常運(yùn)行和良好的性能表現(xiàn)。

如何避免JavaScript中的內(nèi)存泄漏?

另外,通過 Chrome 和 Firefox 的開發(fā)者工具提供的內(nèi)存工具,可以進(jìn)一步探索內(nèi)存使用情況。隊列內(nèi)存使用快照的比較可以顯示在兩個快照之間分配了多少內(nèi)存以及分配的位置,并提供額外信息來幫助識別代碼中存在問題的對象。這些工具為開發(fā)者提供了便利,能夠更好地進(jìn)行內(nèi)存管理和性能優(yōu)化,提高應(yīng)用程序的質(zhì)量和性能。

Java 代碼中常見的內(nèi)存泄漏的常見來源:

研究內(nèi)存泄漏問題就相當(dāng)于尋找符合垃圾回收機(jī)制的編程方式,有效避免對象引用的問題。下面小編就為大家介紹幾個常見的容易導(dǎo)致內(nèi)存泄漏的地方:

1. 全局變量

全局變量始終存儲在根目錄下,且永遠(yuǎn)不會被回收。而在 Java 的開發(fā)中,一些錯誤會導(dǎo)致局部變量被轉(zhuǎn)換到了全局,尤其是在非嚴(yán)格的代碼模式下。下面是兩個常見的局部變量被轉(zhuǎn)化到全局變量的情況:

  1. 為未聲明的變量賦值
  2. 使用 this 指向全局對象。
functioncreateGlobalVariables{

leaking1 = 'I leak into the global scope'; // 為未聲明的變量賦值

this.leaking2 = 'I also leak into the global scope'; // 使用this指向全局對象

};

createGlobalVariables;

window.leaking1;

window.leaking2;

** 注意:** 嚴(yán)格模式("use strict")將幫助您避免上面示例中的內(nèi)存泄漏和控制臺錯誤。

2. 閉包

函數(shù)中定義的變量會在函數(shù)退出調(diào)用棧并且在函數(shù)外部沒有指向它的引用時被清除。而閉包則會保持被引用的變量一直存在,即便函數(shù)的執(zhí)行已經(jīng)終止。

functionouter{

constpotentiallyHugeArray = [];

returnfunctioninner{

potentiallyHugeArray.push('Hello'); // function inner is closed over the potentiallyHugeArray variable

console.log('Hello');

};

};

constsayHello = outer; // contAIns definition of the function inner

functionrepeat(fn, num) {

for(leti = 0; i < num; i++){

fn;

}

}

repeat(sayHello, 10); // each sayHello call pushes another 'Hello' to the potentiallyHugeArray

// now imagine repeat(sayHello, 100000)

在這個例子中,potentiallyHugeArray 從未被任何函數(shù)返回,也無法被訪問,但它的大小會隨著調(diào)用 inner 方法的次數(shù)而增長。

3. 定時器

在 Java 中,使用使用 setTimeout 或 setInterval 函數(shù)引用對象是防止對象被垃圾回收的最常見方法。當(dāng)在代碼中設(shè)置循環(huán)定時器(可以使 setTimeout 表現(xiàn)得像 setInterval,即使其遞歸)時,只要回調(diào)可調(diào)用,定時器回調(diào)對象的引用就會永遠(yuǎn)保持活動狀態(tài)。

例如下面的這段代碼,只有在移除定時器后,data 對象才會被垃圾回收。在沒有移除 setInterval 之前,它永遠(yuǎn)不會被刪除,并且 data.hugeString 會一直保留在內(nèi)存中,直到應(yīng)用程序停止。

functionsetCallback{

constdata = {

counter: 0,

hugeString: newArray(100000).join('x')

};

returnfunctioncb{

data.counter++; // data object is now part of the callback's scope

console.log(data.counter);

}

}

setInterval(setCallback, 1000); // how do we stop it?

那么應(yīng)該如何避免上述這種情況的發(fā)生呢?可以從以下兩個方法入手:

  1. 注意定時器回調(diào)引用的對象。
  2. 必要時取消定時器。

如下方的代碼所示:

functionsetCallback{

// 'unpacking' the data object

letcounter = 0;

consthugeString = newArray(100000).join('x'); // gets removed when the setCallback returns

returnfunctioncb{

counter++; // only counter is part of the callback's scope

console.log(counter);

}

}

consttimerId = setInterval(setCallback, 1000); // saving the interval ID

// doing something ...

clearInterval(timerId); // stopping the timer i.e. if button pressed

4. 事件監(jiān)聽

活動的事件監(jiān)聽器會阻止其范圍內(nèi)的所有變量被回收。一旦添加,事件監(jiān)聽器會一直生效,直到下面兩種情況的發(fā)生:

  1. 通過 removeEventListener 移除。
  2. 相關(guān)聯(lián)的 DOM 元素被移除。

在下面的示例中,使用匿名內(nèi)聯(lián)函數(shù)作為事件監(jiān)聽器,這意味著它不能與 removeEventListener 一起使用。此外,由于 document 不能被移除,觸發(fā)方法中的內(nèi)容會一直駐留內(nèi)存,即使只使用它觸發(fā)一次。

consthugeString = newArray(100000).join('x');

document.addEventListener('keyup', function{ // anonymous inline function - can't remove it

doSomething(hugeString); // hugeString is now forever kept in the callback's scope

});

那么如何避免這種情況呢?可以通過 removeEventListener 釋放監(jiān)聽器:

functionlistener{

doSomething(hugeString);

}

document.addEventListener('keyup', listener); // named function can be referenced here...

document.removeEventListener('keyup', listener); // ...and here

如果事件監(jiān)聽器只需要運(yùn)行一次,addEventListener 可以帶有第三個參數(shù),一個提供附加選項的對象。只要將 {once: true} 作為第三個參數(shù)傳遞給 addEventListener ,監(jiān)聽器將在事件處理一次后自動刪除。

document.addEventListener('keyup', functionlistener{

doSomething(hugeString);

}, {once: true}); // listener will be removed after running once

5. 緩存

如果不斷向緩存中添加內(nèi)容,而未使用的對象也沒有移除,也沒有限制緩存的大小,那么緩存的大小就會無限增長:

letuser_1 = { name: "Peter", id: 12345};

letuser_2 = { name: "Mark", id: 54321};

constmapCache = newMap;

functioncache(obj){

if(!mapCache.has(obj)){

constvalue = `${obj.name}has an id of ${obj.id}`;

mapCache.set(obj, value);

return[value, 'computed'];

}

return[mapCache.get(obj), 'cached'];

}

cache(user_1); // ['Peter has an id of 12345', 'computed']

cache(user_1); // ['Peter has an id of 12345', 'cached']

cache(user_2); // ['Mark has an id of 54321', 'computed']

console.log(mapCache); // ((…) => "Peter has an id of 12345", (…) => "Mark has an id of 54321")

user_1 = null; // removing the inactive user

// Garbage Collector

console.log(mapCache); // ((…) => "Peter has an id of 12345", (…) => "Mark has an id of 54321") // first entry is still in cache

為了解決這個問題,需要清除不需要的緩存:

一種有效的解決內(nèi)存泄漏問題的方法是使用 WeakMap。它是一種數(shù)據(jù)結(jié)構(gòu),其中鍵引用被保持為弱引用,并且僅接受對象作為鍵。如果使用對象作為鍵,并且它是唯一引用該對象的引用,相關(guān)條目將從緩存中移除,并進(jìn)行垃圾回收。在下面的示例中,當(dāng)替換 user_1 后,與之關(guān)聯(lián)的條目將在下一次垃圾回收時自動從 WeakMap 中移除。

letuser_1 = { name: "Peter", id: 12345};

letuser_2 = { name: "Mark", id: 54321};

constweakMapCache = newWeakMap;

functioncache(obj){

// ...same as above, but with weakMapCache

return[weakMapCache.get(obj), 'cached'];

}

cache(user_1); // ['Peter has an id of 12345', 'computed']

cache(user_2); // ['Mark has an id of 54321', 'computed']

console.log(weakMapCache); // ((…) => "Peter has an id of 12345", (…) => "Mark has an id of 54321"}

user_1 = null; // removing the inactive user

// Garbage Collector

console.log(weakMapCache); // ((…) => "Mark has an id of 54321") - first entry gets garbage collected

結(jié)論

對于復(fù)雜的應(yīng)用程序,檢測和修復(fù) Java 內(nèi)存泄漏問題可能是一項非常艱巨的任務(wù)。了解內(nèi)存泄漏的常見原因以防止它們發(fā)生是非常重要的。在涉及內(nèi)存和性能方面,最重要的是用戶體驗(yàn),這才是最重要的。

分享到:
標(biāo)簽:JavaScript
用戶無頭像

網(wǎng)友整理

注冊時間:

網(wǎng)站:5 個   小程序:0 個  文章:12 篇

  • 51998

    網(wǎng)站

  • 12

    小程序

  • 1030137

    文章

  • 747

    會員

趕快注冊賬號,推廣您的網(wǎng)站吧!
最新入駐小程序

數(shù)獨(dú)大挑戰(zhàn)2018-06-03

數(shù)獨(dú)一種數(shù)學(xué)游戲,玩家需要根據(jù)9

答題星2018-06-03

您可以通過答題星輕松地創(chuàng)建試卷

全階人生考試2018-06-03

各種考試題,題庫,初中,高中,大學(xué)四六

運(yùn)動步數(shù)有氧達(dá)人2018-06-03

記錄運(yùn)動步數(shù),積累氧氣值。還可偷

每日養(yǎng)生app2018-06-03

每日養(yǎng)生,天天健康

體育訓(xùn)練成績評定2018-06-03

通用課目體育訓(xùn)練成績評定