2015-05-19 64 views
2

以下代碼會導致節點在耗盡內存時消耗大量內存並導致崩潰。但是,如果我將找到的字符串的長度從13更改爲12,一切都很好。它看起來像由正則表達式搜索返回的字符串包含對被搜索的原始字符串的隱藏引用。但是隻有找到的匹配長度至少爲13個字符。 這是一個錯誤還是有這個行爲的一些很好的理由?節點正則表達式分析器中的內存泄漏?

function randString(length) { 
    var a = "a".charCodeAt(0), 
     result = []; 
    for(var i = 0; i < length; i++) { 
    result.push(a + Math.floor(Math.random() * 26)); 
    } 
    return String.fromCharCode.apply(null, result); 
} 


var arr = []; 

for(var i = 0; i < 1000000; i++) { 
    if(i % 1000 === 0) console.log(i); 
    var str = randString(13); 
    str = randString(5000) + "<" +str + ">" + randString(5000); 
    var re = /<([a-z]+)>/gm; 
    var next = re.exec(str); 
    arr.push(next[1]); 
} 
+0

你確定12個字符的版本不是也使用了大量的內存,但只是不足以讓它崩潰? – robertklep

+0

12個字符的版本使用少於100 MB。但有13個或更多的字符,它將在145,000次迭代中達到1.5GB。 – SpiderPig

+1

我在Chrome中觀察到同樣的情況(版本41.0.2272.76基於Ubuntu 14.04,在LinuxMint 17(64位)上運行) –

回答

1

我在Chrome中觀察到相同的行爲。我認爲這兩個(node.js和Chrome)行爲相同,因爲它們基於相同的Javascript引擎(V8)。

沒有內存泄漏,但在JavaScript中存在垃圾管理問題。我從觀察中扣除了這一點,當我在Google開發工具中強制垃圾收集時,內存的Gbytes被釋放。

您可以強制運行垃圾回收器,如explained here。這樣,你的node.js不會崩潰。

編輯

進一步的測試,我可以告訴這些事情:

關於您的評論但只要還有對陣列無記憶獲取的釋放的引用。

它看起來比這更復雜,但你是對的,arr似乎佔據了所有的空間1.1去100000個項目,這是每個項目10kB。當您查看數組next時,它確實具有大約10kB的大小(10015字節爲next.input。如果所有的工作都像預期的那樣,next[1]將是一個簡單的字符串,並且僅使用略多於13個數據字節,但這不是。情況下,陣列arr中引用next[1]不允許next被垃圾收集

作爲一種解決方案,我想出了這個被修改的碼(fiddle):

function randString(length) { 
    var a = "a".charCodeAt(0), 
     result = []; 
    for(var i = 0; i < length; i++) { 
    result.push(a + Math.floor(Math.random() * 26)); 
    } 
    return String.fromCharCode.apply(null, result); 
} 


var arr = []; 

for(var i = 0; i < 100000; i++) { 
    if(i % 1000 === 0) console.log(i); 
    var str = randString(13); 
    str = randString(5000) + "<" +str + ">" + randString(5000); 
    var re = /<([a-z]+)>/gm; 
    var next = re.exec(str); 
    arr.push(next[1].split('').join('')); 
} 
console.log(arr) 

訣竅是切割參考在next與存儲在中的字符串之間通過拆分字符串並重新加入。

我對內部沒有任何瞭解,但它看起來像是V8中的一個bug。在Firefox上測試相同,一切都按預期工作,並沒有過多的內存使用情況。

+0

運行垃圾收集器沒有任何影響。你可能在一個函數內部定義了'arr',當這個'arr'返回時可以收集垃圾。但只要還有對數組的引用,就不會釋放內存。 – SpiderPig

+0

我無法在node.js上進行測試,但在Google Chrome垃圾回收系統中釋放了大部分內存。看看這個小提琴http://jsfiddle.net/lmeyer1/c2545qmd/2/,運行後點擊*收集垃圾*在devtools的*時間軸*選項卡。 –

+0

好吧,它變得越來越有趣。當我在最後的console.log(arr)(保存引用)時,* Collect垃圾*按鈕不再收集,但是當我第二次啓動時(保持控制檯中的引用),垃圾收集器自動跳入。 –

1

我發現問題的根源。這不是對此負責的正則表達式解析器,而是字符串上的子字符串方法。它的目的是爲了使子串的創建更加高效。 在V8的錯誤報告頁面有一個關於這個問題的公開問題。 https://code.google.com/p/v8/issues/detail?id=2869