vs-streamjsonrpc icon indicating copy to clipboard operation
vs-streamjsonrpc copied to clipboard

Memory leak when returning PipeReader

Open AArnott opened this issue 1 year ago • 1 comments

Discussed in https://github.com/microsoft/vs-streamjsonrpc/discussions/1145

Originally posted by crazyjncsu February 7, 2025 First, sorry, but I have limited familiarity with the inner workings here. But we have some code about like the following:

      using (var multiplexingStream = await MultiplexingStream.CreateAsync(monitoredWebsocket, new MultiplexingStream.Options() { ProtocolMajorVersion = 3 }))
      using (var rpcChannel = await multiplexingStream.AcceptChannelAsync(MultiplexedChannelNames.JSON_RPC))
      using (var formatter = new JsonMessageFormatter() { MultiplexingStream = multiplexingStream })
      using (var headerDelimitedMessageHandler = new HeaderDelimitedMessageHandler(rpcChannel, formatter))
      using (var jsonRpc = new JsonRpc(headerDelimitedMessageHandler, new BackendRPC(this)))
      {
        jsonRpc.CancelLocallyInvokedMethodsWhenConnectionIsClosed = false;
        _agentAPI = jsonRpc.Attach<IOurRpc>();
        jsonRpc.StartListening();

        var finalTask = await Task.WhenAny(multiplexingStream.Completion, jsonRpc.Completion).WithCancellation(_wsConnectionCts.Token);

We yield at Task.WhenAny and you can see the _agentAPI is saved off for others to use.

With IOurRpc looking about like this:

public interface IOurRpc { Task<PipeReader> DoThingAsync(); }

We are calling DoThingAsync, all is working, and we call .Complete() on the resulting PipeReaders (confirmed).

The issue is what we perceive as a memory leak in MessageFormatterDuplexPipeTracker

Upon returning a pipe for consumption, it adds the channel to a list of channels internally:

image

But the only time these are removed are in CleanupInboundResources:

image

... which is not called upon Complete'ing the PipeReader. And is only called upon the ResponseSent from JsonRpc, which does not get called in this case.

So we get gigs and gigs of memory leaked.

My guess is the channel should never be added to inboundRequestChannelMap? I don't know, but I figured an expert here could maybe give it a look?

AArnott avatar Feb 08 '25 18:02 AArnott

Any chance you’ve had a chance to look into this? Do you need any help with the diagnosis?

crazyjncsu avatar Mar 05 '25 07:03 crazyjncsu