我想分析一個相對複雜的Node.js服務器應用程序中的內存/ GC問題。即使在非常適中的負荷下,它在明顯的時段也變得沒有反應,而且這些停頓隨着時間的推移而變長。與--trace-gc
參數運行表明,極長的垃圾收集的時間是有可能的原因:如何在Node.js/V8中調試/分析極長的GC暫停
[4805] 537 ms: Mark-sweep 17.6 (46.4) -> 10.3 (47.4) MB, 20 ms [allocation failure] [GC in old space requested].
[4805] 1338 ms: Mark-sweep 31.3 (58.4) -> 19.2 (57.2) MB, 40 ms [allocation failure] [promotion limit reached].
[4805] 2662 ms: Mark-sweep 58.0 (79.2) -> 43.9 (85.2) MB, 109 ms [Runtime::PerformGC] [promotion limit reached].
[4805] 4014 ms: Mark-sweep 90.1 (111.5) -> 70.6 (113.9) MB, 114 ms [allocation failure] [promotion limit reached].
[4805] 7283 ms: Mark-sweep 129.7 (153.9) -> 112.0 (158.9) MB, 511 ms [allocation failure] [promotion limit reached].
[4805] 10979 ms: Mark-sweep 184.6 (210.9) -> 160.3 (212.9) MB, 422 ms [Runtime::PerformGC] [promotion limit reached].
[4805] 1146869 ms: Mark-sweep 243.8 (271.4) -> 191.6 (267.9) MB, 1856 ms [allocation failure] [promotion limit reached].
[4805] 1731440 ms: Mark-sweep 282.1 (307.4) -> 197.5 (298.9) MB, 1/11230 ms [allocation failure] [promotion limit reached].
[4805] 2024385 ms: Mark-sweep 291.0 (320.8) -> 197.3 (306.9) MB, 9076 ms [Runtime::PerformGC] [promotion limit reached].
[4805] 2623396 ms: Mark-sweep 290.9 (317.1) -> 196.9 (311.9) MB, 1/15401 ms [allocation failure] [promotion limit reached].
[4805] 3223769 ms: Mark-sweep 291.4 (323.6) -> 187.8 (318.9) MB, 1/13385 ms [allocation failure] [promotion limit reached].
[4805] 4225777 ms: Mark-sweep 280.1 (324.2) -> 190.6 (315.9) MB, 1/13266 ms [allocation failure] [promotion limit reached].
[4805] 4705442 ms: Mark-sweep 286.2 (321.4) -> 195.2 (314.9) MB, 1/17256 ms [Runtime::PerformGC] [promotion limit reached].
[4805] 5225595 ms: Mark-sweep 288.3 (324.0) -> 201.7 (316.9) MB, 1/22266 ms [Runtime::PerformGC] [promotion limit reached].
[4805] 6127372 ms: Mark-sweep 296.5 (324.6) -> 200.5 (316.9) MB, 1/28325 ms [allocation failure] [promotion limit reached].
[4805] 6523938 ms: Mark-sweep 297.8 (328.9) -> 198.8 (323.9) MB, 1/27213 ms [allocation failure] [promotion limit reached].
[4805] 7355394 ms: Mark-sweep 292.1 (330.7) -> 223.9 (322.9) MB, 60202 ms [allocation failure] [promotion limit reached].
全(--trace-gc-verbose
)輸出,可以發現here。
這些日誌是用下列參數運行的服務器的結果:
--expose-gc --trace-gc --trace-gc-verbose --trace-gc-ignore-scavenger --max-old-space-size=1000
它運行的時間越長,時間越長暫停得到(通常幾分鐘),直到最終一對夫婦後徹底鎖定了幾小時。可用內存永遠不會用完,RSS甚至不會接近1000mb舊的空間限制,所以它似乎不是泄漏。在我看來,代碼中可能存在一些非常不尋常的東西,使GC在可接受的時間框架內完成工作非常「困難」。
我的問題是:如何進一步分析這個問題,並縮小可能的原因?任何推薦的工具來幫助解決像這樣的問題?我基本上是在尋找一種比天真地關閉代碼部分更高效的方法,這非常麻煩和費時。另外,我非常感謝鏈接到解釋GC調試輸出中使用的術語/消息(例如「達到促銷限制」)的任何文檔,以及那裏列出的數字。我對V8 GC的工作原理有了非常基本的瞭解(this幫了很大忙),但大部分輸出仍然超出了我的想象。
萬一它很重要:它在Ubuntu 14.04服務器上的Node.js v0.10.33上運行。
編輯: 前一段時間,我們轉移到io.js,這裏根本不再發生(大概是由於更近期的V8版本)這個問題。但我從來沒有在Node v0.10上找到這個問題的原因,更不用說修復了。
RSS沒有使用多少內存,至少在所描述的意義上,heapUsed更接近您想要觀看的內容。它看起來像「老指針」是公羊正在去的地方,所以我懷疑封閉被意外緩存,可能是因爲過度慷慨地傳遞了req/res對象。請參閱http://jayconrod.com/posts/55/a-tour-of-v8-garbage-collection – dandavis
上有關此術語和總體的一些詳細信息好處 - heapUsed和heapTotal的圖形完全遵循我監視中的RSS曲線工具,儘管(據我所知,沒有交換)。感謝「舊指針」提示 - 我會更仔細地研究。 – d0gb3r7
,而不是使用嵌套在嵌套在瓶蓋封口原型和OOP受封循環往復 – Esailija