Creating and disposing VL.Audio player leaks memory?

There seems to be memory leaking when repeatedly creating and disposing the audio player.
I have stripped down a patch we have been using on a project. After hours of running the sound playback always broke at some point producing just crackling noises. Now investigating this issue i see memory leaking when the patch is running.

For each sound to play there is an audio player object with audio out created. When the playback ends this object is disposed.

Is there any flaw with the patch structure / logic itself or Vaudio?
I have tried with Asio4All drivers as well as Asio drivers provided by external USB Soundcard.
I am using gamma 2021.3.3 and the current VL.Audio nuget

VAUDIO-TEST.zip (448.8 KB)

EDIT: btw, you do not need to wait hours :P The demo patch breaks quite fast and the leak can be observed in realtime watching taskmanager.
Also it seems after some while, when GC runs peridically the time output on the audio engine stops for a brief moment:
VAUDIO-TEST-Application_2021.07.16-16.00.48

image

i tried with a different audio device and same same. any hint concerning where to look at or to debug this, would be nice. the patch and vvvv does not indicate that something is wrong.

  • it can’t be the soundcard since we tested a couple
  • is this the underlying library, if yes, is there something to look for ? how to debug this visually
  • the testcase is heavy but the real life application with much less soundevents fails too, is there a way to build this more GC friendly ?
  • is this even a GC problem

I changed the test patch a litte to make it easier to control the speed/frequency new particles are added. This way you can run it for some time with a high spread count and then lower it again to see if the wavs are still playing correctly. With 300 something playing at once it’s hard to tell.
I moved the AudioOut from the particle into the root patch to make sure it being in the particle doesn’t cause the issue. The particle dispose function didn’t really dispose of anything so I removed it.

I ran the patch at a high particle spawn rate for some time and then lowered it again multiple times and the playback was fine, no crackling (and memory seems also stable).

Some more things that came to mind while looking at the patch:

Try enabling Dispose Cached Outputs here:

And/Or try adding a Dispose to the AudioPlayer like so:

VAUDIO-TEST_2.vl (29.7 KB)

1 Like

yes, looks like there is the dispose missing in the player.

this is a bit tricky to spot, but any process node that has a Dispose will assign it onto the Dispose of the containing patch. so for example the AudioOut. if there is none, an invisible dispose will be introduced, but if you want to call it explicitly, like in the original patch, you have to add it to call it, even if it looks like nothing is assigned to it.

Oh, this is new to me and feels inconsistent - at least undocumented. Can you please elaborate a bit on that, maybe with an explanatory patch?
Thanks!

1 Like

So to report back on testing, my outcome with the altered patch is different than yours :( I still see memory rising like ~300 MB in 15 min. At that time the audio engine already stops every few sec when memory is freed (it is audible and also can be seen at the time pin). When i switch the spawn rate to low i can already hear first cracks form time to time (the cracking is gradual and gets worse with time). Please note this is yet a completely other machine i am running this on.

Mh, well I didn’t spent too much time on it and only ran it for about 5 min or so on my Laptop. … Wasn’t long enough apparently.

Have you tried adding the Dispose to the AudioPlayer?

Sorry, also forgot to mention that I used some 2021.4 preview because I was too lazy to install 2021.3.3.

Yes i added dispose like in your screenshot. Also checked “dispose cached output”. And tried 2021.4. It did not help :(

Tried my patch again and indeed after hammering it for 10 min the memory usage did increase, then decreased the AudioEngine pausing shortly, like @tgd said. When switching to a lower spawn frequency the playback seemed fine though, maybe I wasn’t patient enough (again).

I gave it another go, making the AudioPlayer a class instead of a process node, getting rid of all cache regions inside and removing some other bits that seemed to be “unnecessary” for the usecase.

While running the updated patch for 15 min the memory didn’t increase. But playback seemed to be somewhat broken afterwards, no crackling but something else, hard to describe.
The part that seems to make the difference (but don’t know for sure & haven’t got the time to dig deeper):
image
The patch contains the modified AudioPlayer.

VAUDIO-TEST_3.vl (91.6 KB)

1 Like

maybe I should have phrased it differently, if you want the Dispose method in the node browser category of your type, you have to add it. the type itself will have it as soon as there is any process node that needs Dispose. so you can also use TryDispose without adding the Dispose explicitly to the type.

So you can think of it like a trickle up that you get for free. if you have 10 levels of nested process nodes, if the innermost has a Dispose, all enclosing ones will get one implicitely, so that the application main patch can dispose on exit.

but if you somehow break the cascade by using a class or record that you create, update and dispose dynamiclly/explicitely (for example particles in a soread), then you have to take care of disposing when the instance isnt needed anymore.

image

AutoDisposable.vl (7.4 KB)

3 Likes

Actually it seems fine to me. After 30 min the memory seems stable too. I need to check more when i am in office tomorrow. thanks so far for taking the time to investigate this.
What i wonder about in your patch is the channel output. When i play one instance at a time (lfo at 6 sec), the sound plays on the left channel. since the file is mono, this makes sense. Strange thing is when playing two instnaces (lfo at 4 sec), the second one is coming from the right channel. It also seems not to finish playback but I cant really tell on my laptop, need to check this too on the big soundcard with more channels.

So this part actually is the fix for the memory leak and the crackling. I have modified our original patch just by adding this. Additionally i set the cache region containing OpenFile to Dispose Cached Outputs too but did not test back without. Guess it does not hurt.
So after running 15 hours overnight the playback is still fine and memory stable. Thank you @bjoern!

@tonfilm: Should a Dispose be added to MultiChannelSignal? Currently it has none.
Something like:

public override void Dispose()
        {
            foreach (AudioSignal item in Outputs)
            {
                Outputs.Remove(item);
       
                if (item != null)
                    item.Dispose();
            }

            base.Dispose();
        }
1 Like

yes, that is definitely an oversight, thanks!

1 Like

i just checked the code and the missing Dispose there is an oversight but not really critical because there are no unmanaged resources allocated.

the issue with the FileStream seems to be here: https://github.com/bj-rn/VVVV.Audio/blob/master/Source/VVVV.Audio.Signals/Sources/FileStreamSignal.cs#L132

this signal needs to Dispose the file reader, which opens the files.

Strange that the patch only started working properly after adding the highlighted part:
image

Turns out this is bad for “normal” playback. A plain audio player node will just run once and break, e.g. when you change the soundfile, it wont play again.
It seems this setting does not affect the other fix when turned off. At least in my rather short test, memory did not increase. I will run the test patch for the night though and report back when i see issues.

yes, this is not the right place to dispose the FileStreamSignal, it should only be disposed when the node itself is disposed. so turning that off is correct.

thanks this is now fixed in VL.Audio 0.3.0-alpha