[英]How to improve the memory usage in nodejs code?
我在hackerearth嘗試了一個代碼: https ://www.hackerearth.com/practice/data-structures/stacks/basics-of-stacks/practice-problems/algorithm/fight-for-laddus/description/
速度似乎不錯,但是內存使用量超過256mb的限制近2.8倍。 在java和python中,內存少5倍,但是時間幾乎是原來的兩倍。
什么因素可用於優化nodejs代碼實現中的內存使用?
這是nodejs的實現:
// Sample code to perform I/O:
process.stdin.resume();
process.stdin.setEncoding("utf-8");
var stdin_input = "";
process.stdin.on("data", function (input) {
stdin_input += input; // Reading input from STDIN
});
process.stdin.on("end", function () {
main(stdin_input);
});
function main(input) {
let arr = input.split("\n");
let testCases = parseInt(arr[0], 10);
arr.splice(0,1);
finalStr = "";
while(testCases > 0){
let inputArray = (arr[arr.length - testCases*2 + 1]).split(" ");
let inputArrayLength = inputArray.length;
testCases = testCases - 1;
frequencyObject = { };
for(let i = 0; i < inputArrayLength; ++i) {
if(!frequencyObject[inputArray[i]])
{
frequencyObject[inputArray[i]] = 0;
}
++frequencyObject[inputArray[i]];
}
let finalArray = [];
finalArray[inputArrayLength-1] = -1;
let stack = [];
stack.push(inputArrayLength-1);
for(let i = inputArrayLength-2; i>=0; i--)
{
let stackLength = stack.length;
while(stackLength > 0 && frequencyObject[inputArray[stack[stackLength-1]]] <= frequencyObject[inputArray[i]])
{
stack.pop();
stackLength--;
}
if (stackLength > 0) {
finalArray[i] = inputArray[stack[stackLength-1]];
} else {
finalArray[i] = -1;
}
stack.push(i);
}
console.log(finalArray.join(" ") + "\n")
}
}
什么因素可用於優化nodejs代碼實現中的內存使用?
這里有一些要考慮的事情:
在處理或輸出數據之前,不要緩存超出您需要的數據。
盡量避免復制數據。 盡可能使用適當的數據。 請記住,所有字符串操作都會創建一個新字符串,該字符串很可能是原始數據的副本。 而且,許多數組操作(如.map()
.filter()
等.filter()
創建原始數組的新副本。
請記住,垃圾回收是延遲的,通常是在空閑時間完成的。 因此,例如,在循環中修改字符串可能會創建許多臨時對象,這些臨時對象必須同時存在,即使在循環完成后大部分或全部將被垃圾回收。 這會導致不良的峰值內存使用率。
正在緩沖
我注意到的第一件事是,您在處理任何輸入文件之前將其讀入內存。 立即為大型輸入文件,您將使用大量內存。 相反,您要做的是讀取足夠多的塊以獲取下一個testCase,然后對其進行處理。
僅供參考,這種增量的讀取/處理將使代碼的編寫變得更加復雜(我自己編寫了一個實現),因為您必須處理部分讀取的行,但是這會占用大量內存,而這正是您要的。
數據副本
將整個輸入文件讀入內存后,您可以使用以下命令立即復制所有文件:
let arr = input.split("\n");
因此,現在您已將輸入數據占用的內存量增加了一倍以上。 現在,不僅所有輸入都只包含一個字符串,您現在仍將所有這些存儲在內存中,但是現在您將其分解為數百個其他字符串(每個字符串都有自己的一點開銷用於新字符串,當然還有每行的副本)。
循環修改字符串
創建最終結果(稱為finalStr
,需要finalStr
進行以下操作:
finalStr = finalStr + finalArray.join(" ") + "\n"
這將創建成千上萬的增量字符串,這些字符串很可能一次都存儲在內存中,因為垃圾回收可能要等到循環結束后才能運行。 例如,如果您有100行輸出,每行100個字符長,所以總輸出(不算行終止符)為100 x 100 = 10,000個字符,則像這樣循環構建,將創建臨時字符串100、200、300、400,... 10,000,這將消耗5000(平均長度)* 100(臨時字符串的數量)= 500,000個字符。 那是臨時字符串對象消耗的總輸出大小的50倍 。
因此,這不僅會創建成噸的增量字符串(每個字符串都比上一個大)(因為您要添加到它上面),而且還會在將所有輸出寫入標准輸出之前在內存中創建整個輸出。
相反,您可以在構造每行時將每行遞增輸出到stdout。 這將使最壞情況下的內存使用量約為輸出大小的2倍,而您的內存使用量則為50倍或更差。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.