簡體   English   中英

如何提高Node.js代碼中的內存使用率?

[英]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代碼實現中的內存使用?

這里有一些要考慮的事情:

  1. 在處理或輸出數據之前,不要緩存超出您需要的數據。

  2. 盡量避免復制數據。 盡可能使用適當的數據。 請記住,所有字符串操作都會創建一個新字符串,該字符串很可能是原始數據的副本。 而且,許多數組操作(如.map() .filter().filter()創建原始數組的新副本。

  3. 請記住,垃圾回收是延遲的,通常是在空閑時間完成的。 因此,例如,在循環中修改字符串可能會創建許多臨時對象,這些臨時對象必須同時存在,即使在循環完成后大部分或全部將被垃圾回收。 這會導致不良的峰值內存使用率。

正在緩沖

我注意到的第一件事是,您在處理任何輸入文件之前將其讀入內存。 立即為大型輸入文件,您將使用大量內存。 相反,您要做的是讀取足夠多的塊以獲取下一個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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM