Skip to content

Commit 66da31a

Browse files
committed
fix: use WeakRef for dep to avoid ReactiveEffect memory leak (vuejs#9233)
1 parent fc76e81 commit 66da31a

File tree

2 files changed

+20
-7
lines changed

2 files changed

+20
-7
lines changed

packages/reactivity/src/dep.ts

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import type { ReactiveEffect } from './effect'
22
import type { ComputedRefImpl } from './computed'
33

4-
export type Dep = Map<ReactiveEffect, number> & {
4+
export type Dep = Map<WeakRef<ReactiveEffect>, number> & {
55
cleanup: () => void
66
computed?: ComputedRefImpl<any>
77
}
@@ -10,7 +10,7 @@ export const createDep = (
1010
cleanup: () => void,
1111
computed?: ComputedRefImpl<any>
1212
): Dep => {
13-
const dep: Dep = new Map() as Dep
13+
const dep = new Map() as Dep
1414
dep.cleanup = cleanup
1515
dep.computed = computed
1616
return dep

packages/reactivity/src/effect.ts

+18-5
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@ export class ReactiveEffect<T = any> {
4646

4747
_dirtyLevel = DirtyLevels.Dirty
4848
_queryingDirty = false
49+
_trackToken = new WeakRef(this)
4950
_trackId = 0
5051
_runnings = 0
5152
_depsLength = 0
@@ -131,9 +132,9 @@ function postCleanupEffect(effect: ReactiveEffect) {
131132
}
132133

133134
function cleanupDepEffect(dep: Dep, effect: ReactiveEffect) {
134-
const trackId = dep.get(effect)
135+
const trackId = dep.get(effect._trackToken)
135136
if (trackId !== undefined && effect._trackId !== trackId) {
136-
dep.delete(effect)
137+
dep.delete(effect._trackToken)
137138
if (dep.size === 0) {
138139
dep.cleanup()
139140
}
@@ -255,8 +256,8 @@ export function trackEffect(
255256
dep: Dep,
256257
debuggerEventExtraInfo?: DebuggerEventExtraInfo
257258
) {
258-
if (dep.get(effect) !== effect._trackId) {
259-
dep.set(effect, effect._trackId)
259+
if (dep.get(effect._trackToken) !== effect._trackId) {
260+
dep.set(effect._trackToken, effect._trackId)
260261
const oldDep = effect.deps[effect._depsLength]
261262
if (oldDep !== dep) {
262263
if (oldDep) {
@@ -281,7 +282,14 @@ export function triggerEffects(
281282
debuggerEventExtraInfo?: DebuggerEventExtraInfo
282283
) {
283284
pauseScheduling()
284-
for (const effect of dep.keys()) {
285+
let reclaimedTokens: WeakRef<ReactiveEffect>[] | undefined
286+
for (const trackToken of dep.keys()) {
287+
const effect = trackToken.deref()
288+
if (!effect) {
289+
reclaimedTokens ??= []
290+
reclaimedTokens.push(trackToken)
291+
continue
292+
}
285293
if (!effect.allowRecurse && effect._runnings) {
286294
continue
287295
}
@@ -303,5 +311,10 @@ export function triggerEffects(
303311
}
304312
}
305313
}
314+
if (reclaimedTokens) {
315+
for (const token of reclaimedTokens) {
316+
dep.delete(token)
317+
}
318+
}
306319
resetScheduling()
307320
}

0 commit comments

Comments
 (0)