Skip to content
This repository has been archived by the owner on Jan 21, 2022. It is now read-only.

leak handler #360

Closed
GoGs99 opened this issue Dec 17, 2017 · 18 comments
Closed

leak handler #360

GoGs99 opened this issue Dec 17, 2017 · 18 comments

Comments

@GoGs99
Copy link

GoGs99 commented Dec 17, 2017

I have an issue / a question (pick one) about Vlc.DotNet.

Generic information

  • Vlc.DotNet version : latest //happening on all versions
  • Vlc.DotNet project used : WinForms
  • libvlc version : 2.2.8 (x86/x64) + videolan.org //happening on all versions
  • .net version : 4
  • Project language :c#
  • Project build architecture : x86
  • Operating system : (Windows 10) (x64)

Summary

when
vlc.endreached
play next file few handlers get leaked.

Stop
play(other file)
every time you do stop and play handle (event) leak

used windows kit
CMD: wpr -start Handle (COLLECT DATA)
DO YOUR START /STOP 100 times
CMD: wpr -stop c:\Handle.etl (SAVE DATA)

use wpa (windows performance analyzer)
cmd: wpa.exe

https://image.ibb.co/d8Yy0R/Capture.jpg

  • [ X] I confirm that my issue doesn't happen in VLC itself.
@jeremyVignelles
Copy link
Collaborator

Did you try with the latest develop version? I think that thinks are getting a little better with that version.
Thanks for your investigations, we definitely need to take care of memory leaks.

@GoGs99
Copy link
Author

GoGs99 commented Dec 18, 2017

I tested the dev version. It's definitely better when playing a video, but not at photos.

To play the picture (in newer versions of the vlc). I use the "--vout=glwin32" option after a long period of time there is a problem "vm3dgl.dll access violation"
Testing 2.2.5.1 without options "--vout=glwin32" Waiting for results.

@GoGs99
Copy link
Author

GoGs99 commented Dec 23, 2017

on 2.2.5.1 lib
moved to WPF
every 1 hour I do dispose...
PLAYER.MediaPlayer.EndReached -= MediaPlayer_EndReached; PLAYER.Dispose(); PLAYER = null;

and recreate:

PLAYER?.Dispose(); PLAYER = new VlcControl(); PLAYER.MediaPlayer.VlcLibDirectory = this.vlcLibDirectory; PLAYER.MediaPlayer.EndReached += MediaPlayer_EndReached; PLAYER.MediaPlayer.VlcMediaplayerOptions = new string[] { "--quiet", "--no-audio" }; PLAYER.MediaPlayer.EndInit(); ControlContainer.Content = PLAYER;

Not helping, is there any more ideas how to properly dispose everything?

@jeremyVignelles
Copy link
Collaborator

I don't really understand your issue.
What kind of things are leaked? Is that managed memory or libvlc things? If it's on libvlc side, I'd recommend using one of the latest 3.0-rc to see how things are going

@GoGs99
Copy link
Author

GoGs99 commented Jan 21, 2018

Simple,
Create player, play a movie, dispose player, create player, play a movie, etc... handle leaked

@dilandau2001
Copy link
Contributor

I have created a small adhoc test to check this issue.
Using latest develop code
Using latest VLC 3.0.4

A winform with 2 buttons and a flowpanel.
Form1Code.txt

I kept creating and destroying players.
And I did evaluate if there was a handle leaking with a memory profiler:

leak

I was not able to reproduce this issue. I found no leak during theses tests.

For the case of end reached, the recomendation to follow is here:
https://github.com/ZeBobo5/Vlc.DotNet/wiki/Vlc.DotNet-freezes-(don't-call-Vlc.DotNet-from-a-Vlc.DotNet-callback)

@dilandau2001
Copy link
Contributor

After some more analisys I see a possible memory leak.
If I just follow the recomendation to restart when end is reached.
I call VlcControl.Play in a new thread.

I have verified that during the GetMedia() process and following steps:
VlcMedia->RegisterEvents is called 3 times
VlcMedia->UnregisterEvents is called once.

For every Player "restart"

Actually, inside VlcMediaPlayer->GetMedia():

`

    public VlcMedia GetMedia()
    {
        var mediaPtr = Manager.GetMediaFromMediaPlayer(myMediaPlayerInstance);
        if (mediaPtr.Pointer != IntPtr.Zero)
            return new VlcMedia(this, mediaPtr);
        return null;
    }

`

If there was already a VlcMedia created, it is returning a new VlcMedia (which calls RegisterEvents) but noone is calling UnregisterEvents from the existing media.

Is it correct to have multiple VlcMedia for a single VlcControl? Could we just store the VlcMedia in a property of the VlcControl so GetMedia just returns it? and then you don't need to create multiple VlcMedias, and you dont need to call Registration so many times.

@dilandau2001
Copy link
Contributor

I confirm the memory leak (if not disposing)

Everytime you SetMedia()
this
LoadedMedias[player].Add(this);
is adding the media to the list of medias. Actually this is called 3 times
GetMedia creates 1
SetMedia creates 1
Manager.SetMediaToMediaPlayer(myMediaPlayerInstance, media.MediaInstance); 1

If you call GetMedia you are actually creating a new one. So anyone using Statistics very often will be having a huge leak.

Disposing the vlcMedia, unregister the attached events, but it does not remove the media from the LoadedMedias...

Stop, does not release medias either.

The only possible way to release everything right now is to dispose the player.

I would not mind to fix it myself although I am not quite sure what is the need of a list of medias per player. (was it related to a playlist or something?, can I force a single VlcMedia per player?)

@jeremyVignelles
Copy link
Collaborator

Thanks for your time. the recommended way in libvlc sample is to release the media reference as soon as set_media has been called.
the release method only decrements the reference count.

I'm not sure how we should handle this.

@jeremyVignelles
Copy link
Collaborator

for reference, here, they release each time a new set media is called : https://code.videolan.org/videolan/vlc-android/blob/master/libvlc/src/org/videolan/libvlc/MediaPlayer.java#L581

So yes, one media per media player, release on SetMedia

@dilandau2001
Copy link
Contributor

I did a small test and modified VlcMediaPlayer to have only one VlcMedia associated.

I confirm in the test that LoadedMedias is 1 all the time, no more increasing per "GetMedia"
I have breakpoints in UnregisterEvents() and RegisterEvents() and I see through breakpoints that Unregister is called before register and only once per "SetMedia". So things are apparently working correctly according to this logic.

But... even though it calls
myVlcMediaPlayer.Manager.DetachEvent(xxxx);

I can see through Memory Diagnostic tools that 6 handlers are leaked on every SetMedia

So with my changes I decrease the memory leak but it is still leaking the handlers... I am totally clueless about why calling DetachEvent is not detaching the handler.

@dilandau2001
Copy link
Contributor

After some more analysis it seems that although the handlers are not inmediatelly released they are disposed eventually so in the long term the memory keeps stable.

Also, if the target is one VlcMedia per player, then VlcMedia can be simplified a lot, most of the work I did in my previous pull #474 is not necessary. The LoadedMedias static dictionary is not necessary, and so the multithread control is not necessary either.

I have test it for a few hours with multiple players with Vlc streaming a 30 seconds video. After many EndReachEvents the memory is still stable.

If @jeremyVignelles don't mind I will add the Sample I was using to the pull. (called Samples.Winforms.MultiplePlayers)

@jeremyVignelles
Copy link
Collaborator

If @jeremyVignelles don't mind I will add the Sample I was using to the pull. (called Samples.Winforms.MultiplePlayers)

Please do :) We need a sample like this.

@dilandau2001
Copy link
Contributor

Done
#477

@GoGs99
Copy link
Author

GoGs99 commented Oct 27, 2018

Thanks dilandau2001.

im using player to play same Videos in loop.
and looking now in code it helped adding dictionary in

VlcMedia.cs

internal static Dictionary<VlcMediaPlayer, List<VlcMedia>> LoadedMedias { get; private set; }
internal VlcMedia(VlcMediaPlayer player, VlcMediaInstance mediaInstance)
        {
            if(!LoadedMedias.ContainsKey(player))
                LoadedMedias[player] = new List<VlcMedia>();
            LoadedMedias[player].Add(this);
            MediaInstance = mediaInstance;
            myVlcMediaPlayer = player;
            RegisterEvents();
        }

in VlcMediaPlayer.cs

private void Dispose(bool disposing)
        {
            if (myMediaPlayerInstance == IntPtr.Zero)
                return;
            UnregisterEvents();
            if (IsPlaying())
                Stop();

            if (VlcMedia.LoadedMedias.ContainsKey(this))
            foreach (var loadedMedia in VlcMedia.LoadedMedias[this])
            {
                loadedMedia.Dispose();
            }
            VlcMedia.LoadedMedias.Remove(this);

            myMediaPlayerInstance.Dispose();
            Manager.Dispose();
        }

it is stupid but definitely to think more about "caching" / ?

@jeremyVignelles
Copy link
Collaborator

@GoGs99 : I don't understand. What do you mean by "caching"? What would you like to cache?

@GoGs99
Copy link
Author

GoGs99 commented Oct 28, 2018

huh, im sorry was 1 year ago, hard to remember why I actually did that...
Somehow by this and some extra code i manage to cache all not finished instances references and then clear them after some time.
To me when Im looking at that its like dispose get call but some handlers not finished and reference to object get lost = handle leak

Edit: Now i see and dilandau2001 says something about that

After some more analysis it seems that although the handlers are not inmediatelly released

@jeremyVignelles
Copy link
Collaborator

It should be fixed in 3.0.0-develop315, can you check it once published to NuGet?

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants