CsWinRT
CsWinRT copied to clipboard
Memory leak when using MediaTrancoder with .Net Stream adapter
I'm using MediaTranscoder WinRT API to convert audio files. It accepts two IRandomAccessStream's, for source and destination data. It works OK when these streams are native WinRT streams, but if I use .Net's FileStream "converted" to IRandomAccessStream (via .AsRandomAccessStream() extension method), I observe a massive memory leak.
To Reproduce
The full project with code to reproduce can be found here: https://github.com/andriysavin/bugreports/tree/main/WinRTMemoryLeakBug. But the basic scenario looks like this (repeated in a loop to make the leak more visible):
var transcoder = new MediaTranscoder();
var encodingProfile = CreateEncodingProfile();
using var dstStream = File.OpenWrite("destination file path").AsRandomAccessStream();
using var srcStream = File.OpenRead("source file path").AsRandomAccessStream();
var prepareOp = await transcoder.PrepareStreamTranscodeAsync(
srcStream,
dstStream,
encodingProfile);
await prepareOp.TranscodeAsync();
Run in VS debugger and observe memory graph in the Diagnostic Tools panel.
In the referenced project I also tried custom stream adapter which does no-op, and still results in memory leak.
Actual behavior
Memory usage is growing, and GCs don't have much effect.
Expected behavior No memory leak
Version Info The TFM I use is net7.0-windows10.0.22000.0, but it doesn't seem to matter, the same happens on net6.0 and other target windows builds.
Additional context
The reason I think this can be related to CsWinRT is that this issue is observed only when I use .Net Stream adapter, and not with native WinRT streams. I don't know if MediaTranscoder has some special logic for native stream implementation, so I assume the issue is .Net-specific. An absolutely blind guess would be that IBuffer instances MediaTranscoder passes to WriteAsync of the stream are not released for some reason and keep being accumulated.
What tells against this theory is that this issue doesn't reproduce on all sound files, only of either certain content and/or format. So that can be a bug in MediaTrancoder as well (still only reproducable with .Net streams).
How this affects me
I use this API in a real service hosted in Azure (continuous WebJob), which transcodes phone calls before storing them in our system. In the recent version I switched from using native streams to .net streams for a number of reasons (e.g. when using native streams, source file often remains open even if I close it, whcih prevents it from deleting, but that's another story). After this change I started observing huge private memory growth in the service process, reaching 10 GB for 24h of run time.
We're also seeing this
Would you mind taking a GC snapshot to see which object is leaking out? This can be done using the memory profiler in VS.
@hez2010 I tried that, but this technique only works for managed memory. The leak is apparently in unmanaged memory (IBuffer), but may be caused by a bug in managed code. You can try it yourself, the link to the sample project is at the top.