看來事件處理閉包會導致DOM節點在引用使用鍵控數據連接的d3.js選擇時泄漏。d3.js內存泄漏事件處理程序關閉中的鍵入連接
爲什麼會發生這種情況?這是d3.js的問題還是它被調用的方式?
此示例泄漏HTMLLIElement
物體時step
反覆調用(clickHandler
不必被執行):
function getKeys(n) {
// returns a random array of n unique Strings, e.g. ["Alpha", "Quebec", "Charlie"]
}
function step() {
function clickHandler() {
// removing this reference removes the leak
// (note that the outer variable is pulled into closure scope regardless of whether this function is called).
listItems;
}
var keys = getKeys(3);
var listItems = d3.selectAll('li')
.data(keys, function(d) { return d });
listItems.enter()
.append('li')
.text(function(d) { return '#' + d })
.on('click', clickHandler)
listItems.exit()
.remove()
}
此模式是可再現與D3.js 3.5 .3並在Chrome 39中可識別。
看來,當兩個條件都滿足DOM節點被泄露:
- 選擇具有鍵功能
- 的封閉,它是用來作爲一個事件處理程序中的選擇的一個節點,具有參考外部範圍選擇。關閉不必執行。
任何這些步驟阻止了內存泄漏:
- 不使用在所述呼叫的鍵功能
data
- 在
step
- 末端添加
listItems = null
避免到外的參考在關閉中選擇 - 在點擊處理關閉中添加
listItems = null
。
後一點是特別有趣,因爲它釋放所有泄漏的節點,而不僅僅是當前listItems
選擇。這意味着選擇是連接的,我沒有想到。
檢查在Chrome DevTools堆快照顯示,泄漏HTMLLIElement
對象在其固定層次兩種不同listItems
:
這是預期的行爲?如果是這樣,是什麼原因造成的這是在我的代碼或d3.js內存泄漏?
N.B.我發現這是我通過避免關閉引用而修復的邏輯錯誤的一部分。我不主張這種模式(因爲它可能導致內存泄漏),但我不明白在這個特定情況下的行爲,因此這個問題。 – joews