概要
Vue.jsでシングルページの中でv-ifを使ってvideo要素を表示したり、非表示にしたりしていたが、その際にMediaStreamに追加したビデオトラックが適切に削除されていなかったため、メモリリークが発生していた。
不具合箇所
mounted() {
this.stream = await navigator.mediaDevices.getUserMedia({ video: true })
}
こんな風にv-ifで作られるたびにメディアストリームを生成してstreamにセットし、video要素のsrcObjectで参照していたが、v-ifでDOMから取り除かれてもメディアストリームに追加されたビデオトラックが削除されていなかったため、メモリリークが発生した?
対策
コンポーネントが破棄される前にちゃんとリソースを解放しておく(下記のような感じ)。
beforeDestroy() {
// video要素
const videoEl = document.querySelector('video')
// ビデオトラックを削除
if (videoEl.srcObject) {
videoEl.srcObject.getVideoTracks().forEach(track => {
track.stop()
videoEl.srcObject.removeTrack(track)
})
}
this.stream = null
videoEl.pause()
videoEl.removeAttribute('srcObject')
videoEl.load()
}
備考
- Chromeではメモリリークっぽいものは発生せず、Safariでだけ発生していた。