ReactiveX / rxjs

A reactive programming library for JavaScript
https://rxjs.dev
Apache License 2.0
30.78k stars 3.01k forks source link

webSocket, WebSocketSubject memory leaks ? #6196

Open usbdem opened 3 years ago

usbdem commented 3 years ago

I am using observable-profiler, and it looks like the WebSocketSubject has a memory leaks.

Should we unsubscribe after this?https://github.com/ReactiveX/rxjs/blob/1e32ed51072f21dd8df79086df329592aff6262e/src/internal/observable/dom/WebSocketSubject.ts#L329

raymonddavis commented 3 years ago

@usbdem Are you sure _connectSocket is being used? The only reference was https://github.com/ReactiveX/rxjs/blob/1e32ed51072f21dd8df79086df329592aff6262e/src/internal/observable/dom/WebSocketSubject.ts#L362 which is deprecated.

Do you have any reproduction steps? Also observable-profiler does show subscriptions as errors if they get release later outside the scope.

usbdem commented 3 years ago

@raymonddavis

@usbdem Are you sure _connectSocket is being used? The only reference was

https://github.com/ReactiveX/rxjs/blob/1e32ed51072f21dd8df79086df329592aff6262e/src/internal/observable/dom/WebSocketSubject.ts#L362

which is deprecated. Do you have any reproduction steps? Also observable-profiler does show subscriptions as errors if they get release later outside the scope.

I put a breakpoint and I see that the _connectSocket is in use:

image

raymonddavis commented 3 years ago

@usbdem I made a stackblitz to try to help. https://stackblitz.com/edit/rxjs-websocket-leak-help If you follow the note and drop a breakpoint in the complete it looks to me that it does get its teardown run.

Can you show the leak from that or provide an example elsewhere of the leak?

Update: I put rxjs-spy in and it does appear the WebSocket is not being destroyed. Please check my logic in case I missed something.

Update 2: Rxjs-spy shows it adding a new WebSocket every time but while looking at the heap snapshot it looks like there is just 1 that does not free.

benlesh commented 3 years ago

@usbdem do you have a complete code reproduction for this?

I suspect that you've got a shareReplay or the like on your socket subject. Because if the ref count gets to 0, in the WebSocketSubject, it will teardown the socket instance and release it. shareReplay, by default, will retain a single connection to the source until it completes unless you pass { refCount: true } to shareReplay.