Skip to content

Commit d1386ac

Browse files
committed
fix: memory leak mutation buffer on stop/start record (#1707)
1 parent 1760cf8 commit d1386ac

File tree

4 files changed

+21
-9
lines changed

4 files changed

+21
-9
lines changed

packages/rrweb-snapshot/src/snapshot.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -332,7 +332,7 @@ function onceIframeLoaded(
332332
if (signal.aborted) return;
333333

334334
const handlers: listenerHandler[] = [];
335-
const removeEventListener = () => handlers.forEach((h) => h())
335+
const removeEventListener = () => handlers.forEach((h) => h());
336336
handlers.push(() => signal.removeEventListener('abort', removeEventListener));
337337
signal.addEventListener('abort', removeEventListener);
338338

@@ -399,7 +399,7 @@ function onceStylesheetLoaded(
399399
if (signal.aborted) return;
400400

401401
const handlers: listenerHandler[] = [];
402-
const removeEventListener = () => handlers.forEach((h) => h())
402+
const removeEventListener = () => handlers.forEach((h) => h());
403403
handlers.push(() => signal.removeEventListener('abort', removeEventListener));
404404
signal.addEventListener('abort', removeEventListener);
405405

packages/rrweb/src/record/mutation.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -526,6 +526,10 @@ export default class MutationBuffer {
526526
this.mutationCb(payload);
527527
};
528528

529+
public destroy() {
530+
this.serializeAbortController.abort();
531+
}
532+
529533
private genTextAreaValueMutation = (textarea: HTMLTextAreaElement) => {
530534
let item = this.attributeMap.get(textarea);
531535
if (!item) {

packages/rrweb/src/record/observer.ts

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -81,7 +81,7 @@ function getEventTarget(event: Event | NonStandardEvent): EventTarget | null {
8181
export function initMutationObserver(
8282
options: MutationBufferParam,
8383
rootEl: Node,
84-
): MutationObserver {
84+
): listenerHandler {
8585
const mutationBuffer = new MutationBuffer();
8686
mutationBuffers.push(mutationBuffer);
8787
// see mutation.ts for details
@@ -99,7 +99,15 @@ export function initMutationObserver(
9999
childList: true,
100100
subtree: true,
101101
});
102-
return observer;
102+
103+
return () => {
104+
observer.disconnect();
105+
mutationBuffer.destroy();
106+
const idx = mutationBuffers.indexOf(mutationBuffer);
107+
if (idx > -1) {
108+
mutationBuffers.splice(idx, 1);
109+
}
110+
};
103111
}
104112

105113
function initMoveObserver({
@@ -1306,9 +1314,9 @@ export function initObservers(
13061314
}
13071315

13081316
mergeHooks(o, hooks);
1309-
let mutationObserver: MutationObserver | undefined;
1317+
let removeMutationObserver: listenerHandler | undefined;
13101318
if (o.recordDOM) {
1311-
mutationObserver = initMutationObserver(o, o.doc);
1319+
removeMutationObserver = initMutationObserver(o, o.doc);
13121320
}
13131321
const mousemoveHandler = initMoveObserver(o);
13141322
const mouseInteractionHandler = initMouseInteractionObserver(o);
@@ -1350,7 +1358,7 @@ export function initObservers(
13501358

13511359
return callbackWrapper(() => {
13521360
mutationBuffers.forEach((b) => b.reset());
1353-
mutationObserver?.disconnect();
1361+
removeMutationObserver?.();
13541362
mousemoveHandler();
13551363
mouseInteractionHandler();
13561364
scrollHandler();

packages/rrweb/src/record/shadow-dom-manager.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@ export class ShadowDomManager {
5353
if (!isNativeShadowDom(shadowRoot)) return;
5454
if (this.shadowDoms.has(shadowRoot)) return;
5555
this.shadowDoms.add(shadowRoot);
56-
const observer = initMutationObserver(
56+
const removeObserver = initMutationObserver(
5757
{
5858
...this.bypassOptions,
5959
doc,
@@ -63,7 +63,7 @@ export class ShadowDomManager {
6363
},
6464
shadowRoot,
6565
);
66-
this.restoreHandlers.push(() => observer.disconnect());
66+
this.restoreHandlers.push(() => removeObserver());
6767
this.restoreHandlers.push(
6868
initScrollObserver({
6969
...this.bypassOptions,

0 commit comments

Comments
 (0)