在幫同事解決問(wèn)題時(shí),經(jīng)常遇到諸如:
- 我沒(méi)有改過(guò)這個(gè)數(shù)據(jù)啊,為什么會(huì)變了...
- 為什么我在頁(yè)面A修改了數(shù)據(jù)烹骨,頁(yè)面B的也會(huì)變
原因通常都是引用類型翻伺,既然引用類型容易引起誤解,那為什么還要設(shè)計(jì)引用類型沮焕?
答案是性能吨岭。
做個(gè)小測(cè)試,循環(huán)一定次數(shù)峦树,給分別給值類型和引用類型賦值辣辫,觀察
- 內(nèi)存占用
- CPU占用
- 耗時(shí)
const cpuStat = require('cpu-stat');
function sub(x1, x2) {
let result = {};
for (const key in x2) {
result[key] = x2[key] - x1[key];
}
return result;
}
function loop(des, func, count) {
return new Promise((resolve) => {
// 強(qiáng)制GC,且在2秒后再運(yùn)行代碼
global.gc();
setTimeout(() => {
cpuStat.usagePercent(function (err, percent, seconds) {
if (err) {
return console.log(err);
}
console.log(`${des}CPU: ${percent}`);
});
const startM = process.memoryUsage();
const startTime = Date.now();
for (let i = 0; i < count; i++) {
func();
}
const endM = process.memoryUsage();
const endTime = Date.now();
console.log(`${des}Memory: ${JSON.stringify(sub(startM, endM), null, 2)}`);
console.log(`${des}Time: ${endTime - startTime}`);
setTimeout(() => {
resolve();
}, 3000)
},2000)
})
}
const count = 2000000000;
async function execute() {
const strSource = '某柏慧燕都非要玩要一二三五點(diǎn)五十旱地';
await loop('str', () => {
let str = strSource;
}, count);
const objSource = { x: strSource };
await loop('obj', () => {
let obj = objSource;
}, count);
}
execute();
運(yùn)行三次的結(jié)果魁巩,平均來(lái)看
引用類型的內(nèi)存占用有巨大的優(yōu)勢(shì)
內(nèi)存
值類型(string)占用內(nèi)存為:2330624字節(jié)
引用類型(object)占用內(nèi)存為:733184字節(jié)
約3倍
耗時(shí)
值類型為:1021毫秒
引用類型為:779毫秒
約1.3倍
CPU占用
值類型為:9.039%
引用類型為:7.960%
約1.13倍
由此可見急灭,引用類型在性能,特別是內(nèi)存占用上有巨大的優(yōu)勢(shì)谷遂。所以葬馋,為了性能,必須要把引用類型弄清楚肾扰。
我們知道畴嘶,計(jì)算機(jī)的臨時(shí)數(shù)據(jù)是存在內(nèi)存中,而每塊內(nèi)存又要有起始地址白对。
換一個(gè)形象的例子:有一排杯子,用來(lái)存東西换怖,每個(gè)杯子上綁了一些線甩恼。杯子表示內(nèi)存,線表示指向內(nèi)存的變量
- 引用類型:每次賦值就是在杯子上綁一根線沉颂,定義1000個(gè)變量=這個(gè)杯子条摸,相當(dāng)于在杯子上綁了1000根線
- 值類型:每次賦值就是加一個(gè)新杯子,并在杯子上綁一線
其中铸屉,杯子就是占用的內(nèi)存钉蒲,線就是定義的變量
image.png
image.png
顯示,對(duì)于
- 引用類型彻坛,其中通過(guò)其中一根獲取到杯子顷啼,并往里面加了水。 對(duì)于綁在杯子上的其它線昌屉,水也增加了钙蒙。
- 對(duì)于值類型,因?yàn)橐桓€只能對(duì)應(yīng)一個(gè)杯子间驮,所以通過(guò)某根線獲取到杯子躬厌,并里面加水,不會(huì)影響到其它線綁定的杯子竞帽。
當(dāng)然扛施,有些語(yǔ)言鸿捧,可以直接操作內(nèi)存,比如C++不僅有指針疙渣,還有指針的指針匙奴,這里就不考慮了。
-------------附運(yùn)行結(jié)果圖------------
image.png
image.png
image.png