Memory leaks 开罗,地面漏水。。。如何使用Monodevelop进行调试?

Memory leaks 开罗,地面漏水。。。如何使用Monodevelop进行调试?,memory-leaks,mono,gtk,cairo,gtk#,Memory Leaks,Mono,Gtk,Cairo,Gtk#,我对Cairo和GTK(运行在.NET和Mono上)有很多疑问。我正在为微软的Windows和Linux开发一个GTK应用程序。我正在使用GTK#2.12 over.NET,而我正在开发应用程序 我创建了一个自定义小部件,它使用Cairo.ImageSurface和Cairo.Context对象。据我所知,我正在调用在小部件代码中创建的每个ImageSurface对象和每个上下文对象的Dispose方法 小部件响应“MouseOver”事件,重新绘制其绘图区域的某些部分 第一个问题: 几乎每一次

我对Cairo和GTK(运行在.NET和Mono上)有很多疑问。我正在为微软的Windows和Linux开发一个GTK应用程序。我正在使用GTK#2.12 over.NET,而我正在开发应用程序

我创建了一个自定义小部件,它使用Cairo.ImageSurface和Cairo.Context对象。据我所知,我正在调用在小部件代码中创建的每个ImageSurface对象和每个上下文对象的Dispose方法

小部件响应“MouseOver”事件,重新绘制其绘图区域的某些部分

第一个问题: 几乎每一次重画操作都会稍微增加内存使用量。当使用的内存量增加了3或4 KB时,Monodevelop tracelog面板会显示以下消息:

开罗。表面泄漏,程序员错过了一个处理调用 将MONO\u CAIRO\u DEBUG\u DISPOSE设置为跟踪分配跟踪

重绘小部件一部分的代码类似于:

// SRGB is a custom struct, not from Gdk nor Cairo
void paintSingleBlock(SRGB color, int i)
{
    using (Cairo.Context g = CairoHelper.Create (GdkWindow)) {
        paintSingleBlock (g, color, i);

        // We do this to avoid memory leaks. Cairo does not work well with the GC.
        g.GetTarget().Dispose ();
        g.Dispose ();
    }
}

void paintSingleBlock(Cairo.Context g, SRGB color, int i)
{
    var scale = Math.Pow (10.0, TimeScale);

    g.Save();
    g.Rectangle (x(i), y(i), w(i), h(i));
    g.ClosePath ();
    g.Restore ();

    // We don't directly use stb.Color because in some cases we need more flexibility
    g.SetSourceRGB (color.R, color.G, color.B);
    g.LineWidth = 0;
    g.Fill ();
}
第二个问题:好的,Monodevelop告诉我应该将
MONO\u CAIRO\u DEBUG\u DISPOSE
设置为“跟踪分配跟踪”(我想是为了找到泄漏)。。。但是我不知道如何设置这个环境变量(我在Windows中)。我尝试过使用bash并执行如下操作:

// SRGB is a custom struct, not from Gdk nor Cairo
void paintSingleBlock(SRGB color, int i)
{
    using (Cairo.Context g = CairoHelper.Create (GdkWindow)) {
        paintSingleBlock (g, color, i);

        // We do this to avoid memory leaks. Cairo does not work well with the GC.
        g.GetTarget().Dispose ();
        g.Dispose ();
    }
}

void paintSingleBlock(Cairo.Context g, SRGB color, int i)
{
    var scale = Math.Pow (10.0, TimeScale);

    g.Save();
    g.Rectangle (x(i), y(i), w(i), h(i));
    g.ClosePath ();
    g.Restore ();

    // We don't directly use stb.Color because in some cases we need more flexibility
    g.SetSourceRGB (color.R, color.G, color.B);
    g.LineWidth = 0;
    g.Fill ();
}
MONO\u CAIRO\u DEBUG\u DISPOSE=1./LightCreator.exe

但在stderr和stdout中都没有出现。。。(无论是出现在Monodevelop的Applicationont跟踪面板中的消息)。我也不知道如何获得在Monodevelop内部看到但没有Monodevelop的调试消息

有没有人有调试GTK或Cairo内存泄漏的经验


提前谢谢。

我只是想把我的2c扔到这里,因为我在开罗用表面处理类似的泄漏问题。我注意到,如果我创建一个曲面对象,ReferenceCount属性将变为1,如果我将该曲面附加到上下文中,if将变为3而不是2。处理上下文后,ReferenceCount返回到2

因此,当我真的想要处理曲面时,我使用了一些反射来调用Cairo中的本机方法来减少ReferenceCount。我使用以下代码:

public static void HardDisposeSurface (this Surface surface)
{
    var handle = surface.Handle;
    long refCount = surface.ReferenceCount;
    surface.Dispose ();
    refCount--;
    if (refCount <= 0)
        return;

    var asm = typeof (Surface).Assembly;
    var nativeMethods = asm.GetType ("Cairo.NativeMethods");
    var surfaceDestroy = nativeMethods.GetMethod ("cairo_surface_destroy", BindingFlags.Static | BindingFlags.NonPublic);
    for (long i = refCount; i > 0; i--)
        surfaceDestroy.Invoke (null, new object [] { handle });
}
公共静态空隙硬处理表面(该表面)
{
var handle=surface.handle;
长引用计数=surface.ReferenceCount;
表面处理();
参考计数--;
if(参考计数0;i--)
Invoke(null,新对象[]{handle});
}

使用它之后,我仍然有一些漏洞,但它们似乎与Cairo的其他部分有关,而与曲面无关。

我发现使用CairoHelper.Create()创建的上下文的引用计数为2

调用dispose可将引用计数减少1。因此,上下文永远不会被释放,也会使其目标保持活动状态

本机对象具有手动引用计数,但Gtk包装器希望保持本机对象处于活动状态,只要存在引用它的C#实例

如果为C#包装器实例创建本机对象,则不需要增加引用计数,因为包装器实例“拥有”本机对象,且引用计数的值正确。但是,如果为已经存在的本机对象创建了包装器实例,则需要手动增加本机对象的引用计数,以使对象保持活动状态

这由创建包装器实例时的bool参数决定

查看CairoHelper.Create()的代码将显示如下内容

public static Cairo.Context Create(Gdk.Window window) {
            IntPtr raw_ret = gdk_cairo_create(window == null ? IntPtr.Zero : window.Handle);
            Cairo.Context ret = new Cairo.Context (raw_ret, false);
            return ret;
        }
即使本机上下文刚刚创建,“owned”将为false,而C#context将增加引用计数

目前没有固定版本,只能通过修复源代码并自行构建Gtk来更正

CairoHelper是一个自动生成的文件,要将参数更改为true,此属性必须包含在gdk/gdk.metadata中

<attr path="/api/namespace/class[@cname='GdkCairo_']/method[@name='Create']/return-type" name="owned">true</attr>

您有什么改进吗?我成功地消除了项目中的所有漏洞。一个来源是
FontOptions
usage。一旦您从上下文中修改fontoptions,它就会开始泄漏…我必须确认是否存在其他潜在源…我还破坏了draw调用之间的所有曲面,我将位图缓存在字节数组中,并在每个周期从中重新创建曲面(必须确认这是绝对必要的)我没有找到任何解决方案:(.无论如何,我还没有发现如何正确调试该问题。我现在没有访问该代码的权限来测试您的建议,但无论如何,这个响应应该得到奖励:)。