C
C#3w ago
noble

How to resolve this unmanaged memory leak?

I've written a small mpv renderer for avalonia using opengl:




So far everything seems to work except when i'm done and call dispose almost no memory involved with the renderer is released even though i destroy the native pointers in a safe way. I'm not sure what i am missing. Any help would be appreciated. For more context, the whole repo is here and readily reproducible: https:///www.github.com/saverinonrails/avaloniampv
4 Replies
noble
nobleOP3w ago
This is the control that actually contains the opengl context and performs the rendering as communicated from the class above:
public class MediaControl : OpenGlControlBase
{
protected unsafe override void OnOpenGlRender(GlInterface gl, int fb)
{
var size = this.Bounds;
var w = (int)size.Width;
var h = (int)size.Height;
var flip_y = 1;
MpvOpenGLFramebuffer framebuffer = new()
{
fbo = fb,
width = w,
height = h,
};
MpvRenderParam[] param = {
new() {
type = mpv_render_param_type.MPV_RENDER_PARAM_OPENGL_FBO,
data = &framebuffer,
},
new() {
type = mpv_render_param_type.MPV_RENDER_PARAM_FLIP_Y,
data = &flip_y,
},
new()
};
fixed (MpvRenderParam* p = &param[0])
{
if (MpvPlayer._mpvRenderContext.isNullPtr()) return;
mpv_render_context_render(MpvPlayer._mpvRenderContext, p);
}
}

internal void TriggerRender()
{
RequestNextFrameRendering();
}

protected override void OnOpenGlInit(GlInterface gl)
{
base.OnOpenGlInit(gl);
MpvPlayer._glInterface = gl;
MpvPlayer._mediaControl = this;
MpvPlayer.Initialise();
}

public static readonly StyledProperty<MpvPlayer> MpvPlayerProperty = AvaloniaProperty.Register<MediaControl, MpvPlayer>(nameof(MpvPlayer));
public MpvPlayer MpvPlayer
{
get => GetValue(MpvPlayerProperty);
set
{
SetValue(MpvPlayerProperty, value);
}
}
}
public class MediaControl : OpenGlControlBase
{
protected unsafe override void OnOpenGlRender(GlInterface gl, int fb)
{
var size = this.Bounds;
var w = (int)size.Width;
var h = (int)size.Height;
var flip_y = 1;
MpvOpenGLFramebuffer framebuffer = new()
{
fbo = fb,
width = w,
height = h,
};
MpvRenderParam[] param = {
new() {
type = mpv_render_param_type.MPV_RENDER_PARAM_OPENGL_FBO,
data = &framebuffer,
},
new() {
type = mpv_render_param_type.MPV_RENDER_PARAM_FLIP_Y,
data = &flip_y,
},
new()
};
fixed (MpvRenderParam* p = &param[0])
{
if (MpvPlayer._mpvRenderContext.isNullPtr()) return;
mpv_render_context_render(MpvPlayer._mpvRenderContext, p);
}
}

internal void TriggerRender()
{
RequestNextFrameRendering();
}

protected override void OnOpenGlInit(GlInterface gl)
{
base.OnOpenGlInit(gl);
MpvPlayer._glInterface = gl;
MpvPlayer._mediaControl = this;
MpvPlayer.Initialise();
}

public static readonly StyledProperty<MpvPlayer> MpvPlayerProperty = AvaloniaProperty.Register<MediaControl, MpvPlayer>(nameof(MpvPlayer));
public MpvPlayer MpvPlayer
{
get => GetValue(MpvPlayerProperty);
set
{
SetValue(MpvPlayerProperty, value);
}
}
}
Kate
Kate3w ago
if the leak is memory allocated in third party native code, you may be able to do an xperf/wpr recording with stacks enabled, and then use WPA to spot the leaked allocations by stacktrace to identify what is being leaked and who is allocating it a likely culprit in a general sense is that the native library you're using may internally be doing some sort of refcounting, and maybe you are not decrementing the reference count enough to trigger resources to be freed. i don't know the code you're working with at all but that is a common way to get leaks
noble
nobleOP3w ago
I see, I basically ported this from mpv-examples , where they rendered onto an sdl opengl context. That sample didn't include much cleanup so I had to guess so it's possible I'm doing something wrong. Perhaps I should search for more examples or try to replicate using libmpv In c first.
Kate
Kate3w ago
it's possible their sample has a leak. i'd investigate that first. on modern hardware you can get away with severe leaks without noticing

Did you find this page helpful?