开罗的记忆泄露

Memory leaks with Cairo

本文关键字:记忆      更新时间:2023-10-16

这是我第一次使用Cairo。我使用以下功能创建曲面:

//This function should give us a new x11 surface to draw on.
cairo_surface_t *create_x11_surface(Display *d, int *x, int *y) {
    Drawable da;
    int screen;
    cairo_surface_t *sfc;
    Screen *scr;
    screen = DefaultScreen(d);
    scr = DefaultScreenOfDisplay(d);
    if (!*x || !*y) {
        *x = WidthOfScreen(scr) / 2;
        *y = HeightOfScreen(scr) / 2;
        da =
            XCreateSimpleWindow(d, DefaultRootWindow(d), 0, 0, *x, *y, 0, 0, 0);
    } else
        da =
            XCreateSimpleWindow(d, DefaultRootWindow(d), 0, 0, *x, *y, 0, 0, 0);
    XSelectInput(d, da, ButtonPressMask | ButtonReleaseMask | KeyPressMask |
                            ButtonMotionMask | StructureNotifyMask);
    // http://www.lemoda.net/c/xlib-wmclose/index.html
    /* "wm_delete_window" is the Atom which corresponds to the delete
           window message sent by the window manager. */
    Atom wm_delete_window;
    wm_delete_window = XInternAtom(d, "WM_DELETE_WINDOW", False);
    /* Set up the window manager protocols. The third argument here is
       meant to be an array, and the fourth argument is the size of
       the array. */
    XSetWMProtocols(d, da, &wm_delete_window, 1);
    XMapWindow(d, da);
    sfc = cairo_xlib_surface_create(d, da, DefaultVisual(d, screen), *x, *y);
    return sfc;
}

我的main()包括创建一个Drawer对象并调用其run方法。Drawer定义如下(略为简化,未显示未使用的模板参数):

struct Drawer {
    Drawer() {
        d = XOpenDisplay(NULL);
        if (d == NULL) {
            fprintf(stderr, "Failed to open displayn");
            exit(-1);
        }
        // create a new cairo surface in an x11 window as well as a cairo_t* to
        // draw on the x11 window with.
        int x=500, y=500;
        surface = create_x11_surface(d, &x, &y);
        cr = cairo_create(surface);
    }
    // https://stackoverflow.com/a/19308254/2725810
    ~Drawer() {
        cairo_destroy(cr);
        cairo_surface_destroy(surface);
        XCloseDisplay(d);
    }
    // Returns true if need to continue or false if quiting
    bool processEvents() {
        XEvent e;
        if (XPending(cairo_xlib_surface_get_display(surface))) {
            XNextEvent(cairo_xlib_surface_get_display(surface), &e);
            switch (e.type) {
            case ButtonPress:
                drag_start_x = e.xbutton.x;
                drag_start_y = e.xbutton.y;
                break;
            case ButtonRelease:
                last_delta_x = 0;
                last_delta_y = 0;
                break;
            case MotionNotify:
                // http://cairographics.org/manual/cairo-Transformations.html#cairo-translate
                cairo_translate(cr, e.xmotion.x - drag_start_x - last_delta_x,
                                e.xmotion.y - drag_start_y - last_delta_y);
                last_delta_x = e.xmotion.x - drag_start_x;
                last_delta_y = e.xmotion.y - drag_start_y;
                break;
            case ConfigureNotify:
                cairo_xlib_surface_set_size(surface, e.xconfigure.width,
                                            e.xconfigure.height);
                break;
            case ClientMessage:
                return false;
            default:
                fprintf(stderr, "Dropping unhandled XEevent.type = %d.n",
                        e.type);
            }
        }
        return true;
    }
    void draw() {
        cairo_push_group(cr);
        // Clear the background
        cairo_set_source_rgb(cr, 0, 0, 0);
        cairo_paint(cr);
        cairo_set_source_rgb(cr, 0, 1, 0);
        cairo_move_to(cr, 0, 0);
        cairo_line_to(cr, 256, 256);
        cairo_move_to(cr, 256, 0);
        cairo_line_to(cr, 0, 256);
        cairo_set_line_width(cr, 10.0);
        cairo_stroke(cr);
        cairo_pop_group_to_source(cr);
        cairo_paint(cr);
        cairo_surface_flush(surface);
        XFlush(d);
    }
    void run() {
        while (1) {
            if (!processEvents()) break;
            draw();
            sleep(0.1);
        }
    }
private:
    Display *d;
    cairo_surface_t* surface;
    cairo_t* cr;
    int last_delta_x = 0, last_delta_y = 0;
    int drag_start_x, drag_start_y;
};

该程序采用gcc 4.8.2版本编译。

valgrind报告内存泄漏,并指出对cairo_stroke和其他Cairo函数的调用是泄漏的原因。它还说,尽管调用了Drawer的析构函数,但当程序完成时,一些内存仍然没有释放。以下是valgrind:的输出

==6897== Memcheck, a memory error detector
==6897== Copyright (C) 2002-2013, and GNU GPL'd, by Julian Seward et al.
==6897== Using Valgrind-3.10.0.SVN and LibVEX; rerun with -h for copyright info
==6897== Command: ./Test
==6897== 
Dropping unhandled XEevent.type = 21.
Dropping unhandled XEevent.type = 19.
Dropping unhandled XEevent.type = 65.
==6897== 
==6897== HEAP SUMMARY:
==6897==     in use at exit: 12,696 bytes in 12 blocks
==6897==   total heap usage: 19,039 allocs, 19,027 frees, 8,088,426 bytes allocated
==6897== 
==6897== 72 bytes in 1 blocks are still reachable in loss record 1 of 11
==6897==    at 0x4C2AB80: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==6897==    by 0x4E59F7C: ??? (in /usr/lib/x86_64-linux-gnu/libcairo.so.2.11301.0)
==6897==    by 0x4E5B5B9: ??? (in /usr/lib/x86_64-linux-gnu/libcairo.so.2.11301.0)
==6897==    by 0x4E5BAE5: ??? (in /usr/lib/x86_64-linux-gnu/libcairo.so.2.11301.0)
==6897==    by 0x4E5CAB0: ??? (in /usr/lib/x86_64-linux-gnu/libcairo.so.2.11301.0)
==6897==    by 0x4E5D87D: ??? (in /usr/lib/x86_64-linux-gnu/libcairo.so.2.11301.0)
==6897==    by 0x4EA2050: ??? (in /usr/lib/x86_64-linux-gnu/libcairo.so.2.11301.0)
==6897==    by 0x4EA3142: ??? (in /usr/lib/x86_64-linux-gnu/libcairo.so.2.11301.0)
==6897==    by 0x4E5FECF: ??? (in /usr/lib/x86_64-linux-gnu/libcairo.so.2.11301.0)
==6897==    by 0x4E57F01: cairo_push_group_with_content (in /usr/lib/x86_64-linux-gnu/libcairo.so.2.11301.0)
==6897==    by 0x40590D: Drawer<NoGraph<StateNeighbor<Pancake, true> > >::draw() (Drawer.h:115)
==6897==    by 0x403A7A: Drawer<NoGraph<StateNeighbor<Pancake, true> > >::run() (Drawer.h:138)
==6897== 
==6897== 72 bytes in 1 blocks are still reachable in loss record 2 of 11
==6897==    at 0x4C2AB80: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==6897==    by 0x4E59F7C: ??? (in /usr/lib/x86_64-linux-gnu/libcairo.so.2.11301.0)
==6897==    by 0x4E5B5B9: ??? (in /usr/lib/x86_64-linux-gnu/libcairo.so.2.11301.0)
==6897==    by 0x4E5BAE5: ??? (in /usr/lib/x86_64-linux-gnu/libcairo.so.2.11301.0)
==6897==    by 0x4E5CDB2: ??? (in /usr/lib/x86_64-linux-gnu/libcairo.so.2.11301.0)
==6897==    by 0x4EB4DE3: ??? (in /usr/lib/x86_64-linux-gnu/libcairo.so.2.11301.0)
==6897==    by 0x4E5DA63: ??? (in /usr/lib/x86_64-linux-gnu/libcairo.so.2.11301.0)
==6897==    by 0x4ECEA3C: ??? (in /usr/lib/x86_64-linux-gnu/libcairo.so.2.11301.0)
==6897==    by 0x4EA2411: ??? (in /usr/lib/x86_64-linux-gnu/libcairo.so.2.11301.0)
==6897==    by 0x4E651E1: ??? (in /usr/lib/x86_64-linux-gnu/libcairo.so.2.11301.0)
==6897==    by 0x4E5F168: ??? (in /usr/lib/x86_64-linux-gnu/libcairo.so.2.11301.0)
==6897==    by 0x4E58994: cairo_stroke (in /usr/lib/x86_64-linux-gnu/libcairo.so.2.11301.0)
==6897== 
==6897== 160 bytes in 1 blocks are still reachable in loss record 3 of 11
==6897==    at 0x4C2AB80: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==6897==    by 0x4E850BC: ??? (in /usr/lib/x86_64-linux-gnu/libcairo.so.2.11301.0)
==6897==    by 0x4E851BC: cairo_pattern_create_rgba (in /usr/lib/x86_64-linux-gnu/libcairo.so.2.11301.0)
==6897==    by 0x4E6028A: ??? (in /usr/lib/x86_64-linux-gnu/libcairo.so.2.11301.0)
==6897==    by 0x4E57FC9: cairo_set_source_rgb (in /usr/lib/x86_64-linux-gnu/libcairo.so.2.11301.0)
==6897==    by 0x405959: Drawer<NoGraph<StateNeighbor<Pancake, true> > >::draw() (Drawer.h:121)
==6897==    by 0x403A7A: Drawer<NoGraph<StateNeighbor<Pancake, true> > >::run() (Drawer.h:138)
==6897==    by 0x402269: main (Test.cpp:48)
==6897== 
==6897== 256 bytes in 2 blocks are still reachable in loss record 4 of 11
==6897==    at 0x4C2AB80: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==6897==    by 0x4E8529A: cairo_pattern_create_for_surface (in /usr/lib/x86_64-linux-gnu/libcairo.so.2.11301.0)
==6897==    by 0x4E5FD7F: ??? (in /usr/lib/x86_64-linux-gnu/libcairo.so.2.11301.0)
==6897==    by 0x4E57F48: cairo_pop_group (in /usr/lib/x86_64-linux-gnu/libcairo.so.2.11301.0)
==6897==    by 0x4E5809D: cairo_pop_group_to_source (in /usr/lib/x86_64-linux-gnu/libcairo.so.2.11301.0)
==6897==    by 0x405A38: Drawer<NoGraph<StateNeighbor<Pancake, true> > >::draw() (Drawer.h:129)
==6897==    by 0x403A7A: Drawer<NoGraph<StateNeighbor<Pancake, true> > >::run() (Drawer.h:138)
==6897==    by 0x402269: main (Test.cpp:48)
==6897== 
==6897== 352 bytes in 1 blocks are definitely lost in loss record 5 of 11
==6897==    at 0x4C2AB80: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==6897==    by 0x4ECC831: ??? (in /usr/lib/x86_64-linux-gnu/libcairo.so.2.11301.0)
==6897==    by 0x4ECC933: ??? (in /usr/lib/x86_64-linux-gnu/libcairo.so.2.11301.0)
==6897==    by 0x4ECD497: ??? (in /usr/lib/x86_64-linux-gnu/libcairo.so.2.11301.0)
==6897==    by 0x4EB3922: ??? (in /usr/lib/x86_64-linux-gnu/libcairo.so.2.11301.0)
==6897==    by 0x4EB4E32: ??? (in /usr/lib/x86_64-linux-gnu/libcairo.so.2.11301.0)
==6897==    by 0x4E5DA63: ??? (in /usr/lib/x86_64-linux-gnu/libcairo.so.2.11301.0)
==6897==    by 0x4ECEA3C: ??? (in /usr/lib/x86_64-linux-gnu/libcairo.so.2.11301.0)
==6897==    by 0x4EA2411: ??? (in /usr/lib/x86_64-linux-gnu/libcairo.so.2.11301.0)
==6897==    by 0x4E651E1: ??? (in /usr/lib/x86_64-linux-gnu/libcairo.so.2.11301.0)
==6897==    by 0x4E5F168: ??? (in /usr/lib/x86_64-linux-gnu/libcairo.so.2.11301.0)
==6897==    by 0x4E58994: cairo_stroke (in /usr/lib/x86_64-linux-gnu/libcairo.so.2.11301.0)
==6897== 
==6897== 1,424 bytes in 1 blocks are still reachable in loss record 6 of 11
==6897==    at 0x4C2AB80: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==6897==    by 0x4E604E7: ??? (in /usr/lib/x86_64-linux-gnu/libcairo.so.2.11301.0)
==6897==    by 0x403A04: Drawer<NoGraph<StateNeighbor<Pancake, true> > >::Drawer(NoGraph<StateNeighbor<Pancake, true> > const&) (Drawer.h:66)
==6897==    by 0x40225D: main (Test.cpp:47)
==6897== 
==6897== 2,072 bytes in 1 blocks are still reachable in loss record 7 of 11
==6897==    at 0x4C2AB80: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==6897==    by 0x5FCCE9A: ??? (in /usr/lib/x86_64-linux-gnu/libpixman-1.so.0.30.2)
==6897==    by 0x5FCBACE: ??? (in /usr/lib/x86_64-linux-gnu/libpixman-1.so.0.30.2)
==6897==    by 0x5FCD585: ??? (in /usr/lib/x86_64-linux-gnu/libpixman-1.so.0.30.2)
==6897==    by 0x5F7F508: ??? (in /usr/lib/x86_64-linux-gnu/libpixman-1.so.0.30.2)
==6897==    by 0x4010139: call_init.part.0 (dl-init.c:78)
==6897==    by 0x4010222: _dl_init (dl-init.c:36)
==6897==    by 0x4001309: ??? (in /lib/x86_64-linux-gnu/ld-2.19.so)
==6897== 
==6897== 2,072 bytes in 1 blocks are still reachable in loss record 8 of 11
==6897==    at 0x4C2AB80: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==6897==    by 0x5FCCE9A: ??? (in /usr/lib/x86_64-linux-gnu/libpixman-1.so.0.30.2)
==6897==    by 0x5FCA61F: ??? (in /usr/lib/x86_64-linux-gnu/libpixman-1.so.0.30.2)
==6897==    by 0x5FCD5A0: ??? (in /usr/lib/x86_64-linux-gnu/libpixman-1.so.0.30.2)
==6897==    by 0x5F7F508: ??? (in /usr/lib/x86_64-linux-gnu/libpixman-1.so.0.30.2)
==6897==    by 0x4010139: call_init.part.0 (dl-init.c:78)
==6897==    by 0x4010222: _dl_init (dl-init.c:36)
==6897==    by 0x4001309: ??? (in /lib/x86_64-linux-gnu/ld-2.19.so)
==6897== 
==6897== 2,072 bytes in 1 blocks are still reachable in loss record 9 of 11
==6897==    at 0x4C2AB80: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==6897==    by 0x5FCCE9A: ??? (in /usr/lib/x86_64-linux-gnu/libpixman-1.so.0.30.2)
==6897==    by 0x5FE5A8F: ??? (in /usr/lib/x86_64-linux-gnu/libpixman-1.so.0.30.2)
==6897==    by 0x5FBC1A5: ??? (in /usr/lib/x86_64-linux-gnu/libpixman-1.so.0.30.2)
==6897==    by 0x5FCD5AB: ??? (in /usr/lib/x86_64-linux-gnu/libpixman-1.so.0.30.2)
==6897==    by 0x5F7F508: ??? (in /usr/lib/x86_64-linux-gnu/libpixman-1.so.0.30.2)
==6897==    by 0x4010139: call_init.part.0 (dl-init.c:78)
==6897==    by 0x4010222: _dl_init (dl-init.c:36)
==6897==    by 0x4001309: ??? (in /lib/x86_64-linux-gnu/ld-2.19.so)
==6897== 
==6897== 2,072 bytes in 1 blocks are still reachable in loss record 10 of 11
==6897==    at 0x4C2AB80: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==6897==    by 0x5FCCE9A: ??? (in /usr/lib/x86_64-linux-gnu/libpixman-1.so.0.30.2)
==6897==    by 0x60053CF: ??? (in /usr/lib/x86_64-linux-gnu/libpixman-1.so.0.30.2)
==6897==    by 0x5FCD5AB: ??? (in /usr/lib/x86_64-linux-gnu/libpixman-1.so.0.30.2)
==6897==    by 0x5F7F508: ??? (in /usr/lib/x86_64-linux-gnu/libpixman-1.so.0.30.2)
==6897==    by 0x4010139: call_init.part.0 (dl-init.c:78)
==6897==    by 0x4010222: _dl_init (dl-init.c:36)
==6897==    by 0x4001309: ??? (in /lib/x86_64-linux-gnu/ld-2.19.so)
==6897== 
==6897== 2,072 bytes in 1 blocks are still reachable in loss record 11 of 11
==6897==    at 0x4C2AB80: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==6897==    by 0x5FCCE9A: ??? (in /usr/lib/x86_64-linux-gnu/libpixman-1.so.0.30.2)
==6897==    by 0x5FCFCBF: ??? (in /usr/lib/x86_64-linux-gnu/libpixman-1.so.0.30.2)
==6897==    by 0x5F7F508: ??? (in /usr/lib/x86_64-linux-gnu/libpixman-1.so.0.30.2)
==6897==    by 0x4010139: call_init.part.0 (dl-init.c:78)
==6897==    by 0x4010222: _dl_init (dl-init.c:36)
==6897==    by 0x4001309: ??? (in /lib/x86_64-linux-gnu/ld-2.19.so)
==6897== 
==6897== LEAK SUMMARY:
==6897==    definitely lost: 352 bytes in 1 blocks
==6897==    indirectly lost: 0 bytes in 0 blocks
==6897==      possibly lost: 0 bytes in 0 blocks
==6897==    still reachable: 12,344 bytes in 11 blocks
==6897==         suppressed: 0 bytes in 0 blocks
==6897== 
==6897== For counts of detected and suppressed errors, rerun with: -v
==6897== ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 0 from 0)

我做什么不对?

UPDATE:按照这里的建议,从析构函数插入对cairo_debug_reset_static_data()的调用后,valgrind的输出变得更短:

==7310== Memcheck, a memory error detector
==7310== Copyright (C) 2002-2013, and GNU GPL'd, by Julian Seward et al.
==7310== Using Valgrind-3.10.0.SVN and LibVEX; rerun with -h for copyright info
==7310== Command: ./Test
==7310== 
Dropping unhandled XEevent.type = 21.
Dropping unhandled XEevent.type = 19.
Dropping unhandled XEevent.type = 65.
==7310== 
==7310== HEAP SUMMARY:
==7310==     in use at exit: 10,712 bytes in 6 blocks
==7310==   total heap usage: 29,352 allocs, 29,346 frees, 12,459,938 bytes allocated
==7310== 
==7310== 352 bytes in 1 blocks are definitely lost in loss record 1 of 6
==7310==    at 0x4C2AB80: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==7310==    by 0x4ECC831: ??? (in /usr/lib/x86_64-linux-gnu/libcairo.so.2.11301.0)
==7310==    by 0x4ECC933: ??? (in /usr/lib/x86_64-linux-gnu/libcairo.so.2.11301.0)
==7310==    by 0x4ECD497: ??? (in /usr/lib/x86_64-linux-gnu/libcairo.so.2.11301.0)
==7310==    by 0x4EB3922: ??? (in /usr/lib/x86_64-linux-gnu/libcairo.so.2.11301.0)
==7310==    by 0x4EB4E32: ??? (in /usr/lib/x86_64-linux-gnu/libcairo.so.2.11301.0)
==7310==    by 0x4E5DA63: ??? (in /usr/lib/x86_64-linux-gnu/libcairo.so.2.11301.0)
==7310==    by 0x4ECEA3C: ??? (in /usr/lib/x86_64-linux-gnu/libcairo.so.2.11301.0)
==7310==    by 0x4EA2411: ??? (in /usr/lib/x86_64-linux-gnu/libcairo.so.2.11301.0)
==7310==    by 0x4E651E1: ??? (in /usr/lib/x86_64-linux-gnu/libcairo.so.2.11301.0)
==7310==    by 0x4E5F168: ??? (in /usr/lib/x86_64-linux-gnu/libcairo.so.2.11301.0)
==7310==    by 0x4E58994: cairo_stroke (in /usr/lib/x86_64-linux-gnu/libcairo.so.2.11301.0)
==7310== 
==7310== 2,072 bytes in 1 blocks are still reachable in loss record 2 of 6
==7310==    at 0x4C2AB80: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==7310==    by 0x5FCCE9A: ??? (in /usr/lib/x86_64-linux-gnu/libpixman-1.so.0.30.2)
==7310==    by 0x5FCBACE: ??? (in /usr/lib/x86_64-linux-gnu/libpixman-1.so.0.30.2)
==7310==    by 0x5FCD585: ??? (in /usr/lib/x86_64-linux-gnu/libpixman-1.so.0.30.2)
==7310==    by 0x5F7F508: ??? (in /usr/lib/x86_64-linux-gnu/libpixman-1.so.0.30.2)
==7310==    by 0x4010139: call_init.part.0 (dl-init.c:78)
==7310==    by 0x4010222: _dl_init (dl-init.c:36)
==7310==    by 0x4001309: ??? (in /lib/x86_64-linux-gnu/ld-2.19.so)
==7310== 
==7310== 2,072 bytes in 1 blocks are still reachable in loss record 3 of 6
==7310==    at 0x4C2AB80: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==7310==    by 0x5FCCE9A: ??? (in /usr/lib/x86_64-linux-gnu/libpixman-1.so.0.30.2)
==7310==    by 0x5FCA61F: ??? (in /usr/lib/x86_64-linux-gnu/libpixman-1.so.0.30.2)
==7310==    by 0x5FCD5A0: ??? (in /usr/lib/x86_64-linux-gnu/libpixman-1.so.0.30.2)
==7310==    by 0x5F7F508: ??? (in /usr/lib/x86_64-linux-gnu/libpixman-1.so.0.30.2)
==7310==    by 0x4010139: call_init.part.0 (dl-init.c:78)
==7310==    by 0x4010222: _dl_init (dl-init.c:36)
==7310==    by 0x4001309: ??? (in /lib/x86_64-linux-gnu/ld-2.19.so)
==7310== 
==7310== 2,072 bytes in 1 blocks are still reachable in loss record 4 of 6
==7310==    at 0x4C2AB80: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==7310==    by 0x5FCCE9A: ??? (in /usr/lib/x86_64-linux-gnu/libpixman-1.so.0.30.2)
==7310==    by 0x5FE5A8F: ??? (in /usr/lib/x86_64-linux-gnu/libpixman-1.so.0.30.2)
==7310==    by 0x5FBC1A5: ??? (in /usr/lib/x86_64-linux-gnu/libpixman-1.so.0.30.2)
==7310==    by 0x5FCD5AB: ??? (in /usr/lib/x86_64-linux-gnu/libpixman-1.so.0.30.2)
==7310==    by 0x5F7F508: ??? (in /usr/lib/x86_64-linux-gnu/libpixman-1.so.0.30.2)
==7310==    by 0x4010139: call_init.part.0 (dl-init.c:78)
==7310==    by 0x4010222: _dl_init (dl-init.c:36)
==7310==    by 0x4001309: ??? (in /lib/x86_64-linux-gnu/ld-2.19.so)
==7310== 
==7310== 2,072 bytes in 1 blocks are still reachable in loss record 5 of 6
==7310==    at 0x4C2AB80: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==7310==    by 0x5FCCE9A: ??? (in /usr/lib/x86_64-linux-gnu/libpixman-1.so.0.30.2)
==7310==    by 0x60053CF: ??? (in /usr/lib/x86_64-linux-gnu/libpixman-1.so.0.30.2)
==7310==    by 0x5FCD5AB: ??? (in /usr/lib/x86_64-linux-gnu/libpixman-1.so.0.30.2)
==7310==    by 0x5F7F508: ??? (in /usr/lib/x86_64-linux-gnu/libpixman-1.so.0.30.2)
==7310==    by 0x4010139: call_init.part.0 (dl-init.c:78)
==7310==    by 0x4010222: _dl_init (dl-init.c:36)
==7310==    by 0x4001309: ??? (in /lib/x86_64-linux-gnu/ld-2.19.so)
==7310== 
==7310== 2,072 bytes in 1 blocks are still reachable in loss record 6 of 6
==7310==    at 0x4C2AB80: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==7310==    by 0x5FCCE9A: ??? (in /usr/lib/x86_64-linux-gnu/libpixman-1.so.0.30.2)
==7310==    by 0x5FCFCBF: ??? (in /usr/lib/x86_64-linux-gnu/libpixman-1.so.0.30.2)
==7310==    by 0x5F7F508: ??? (in /usr/lib/x86_64-linux-gnu/libpixman-1.so.0.30.2)
==7310==    by 0x4010139: call_init.part.0 (dl-init.c:78)
==7310==    by 0x4010222: _dl_init (dl-init.c:36)
==7310==    by 0x4001309: ??? (in /lib/x86_64-linux-gnu/ld-2.19.so)
==7310== 
==7310== LEAK SUMMARY:
==7310==    definitely lost: 352 bytes in 1 blocks
==7310==    indirectly lost: 0 bytes in 0 blocks
==7310==      possibly lost: 0 bytes in 0 blocks
==7310==    still reachable: 10,360 bytes in 5 blocks
==7310==         suppressed: 0 bytes in 0 blocks
==7310== 
==7310== For counts of detected and suppressed errors, rerun with: -v
==7310== ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 0 from 0)

顺便说一句,为什么valgrind不显示丢失记录的完整调用堆栈,而是停在cairo_stroke?我的程序是用带有-g标志的gcc编译的。。。

UPDATE:正如评论中所要求的,以下是整个工作示例:

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <cairo-xlib.h>
#include <X11/Xlib.h>
#include <X11/Xatom.h>
#include <X11/Xutil.h>
#include <unistd.h>
//This function should give us a new x11 surface to draw on.
cairo_surface_t *create_x11_surface(Display *d, int *x, int *y) {
    Drawable da;
    int screen;
    cairo_surface_t *sfc;
    Screen *scr;
    screen = DefaultScreen(d);
    scr = DefaultScreenOfDisplay(d);
    if (!*x || !*y) {
        *x = WidthOfScreen(scr) / 2;
        *y = HeightOfScreen(scr) / 2;
        da =
            XCreateSimpleWindow(d, DefaultRootWindow(d), 0, 0, *x, *y, 0, 0, 0);
    } else
        da =
            XCreateSimpleWindow(d, DefaultRootWindow(d), 0, 0, *x, *y, 0, 0, 0);
    XSelectInput(d, da, ButtonPressMask | ButtonReleaseMask | KeyPressMask |
                            ButtonMotionMask | StructureNotifyMask);
    // http://www.lemoda.net/c/xlib-wmclose/index.html
    /* "wm_delete_window" is the Atom which corresponds to the delete
           window message sent by the window manager. */
    Atom wm_delete_window;
    wm_delete_window = XInternAtom(d, "WM_DELETE_WINDOW", False);
    /* Set up the window manager protocols. The third argument here is
       meant to be an array, and the fourth argument is the size of
       the array. */
    XSetWMProtocols(d, da, &wm_delete_window, 1);
    XMapWindow(d, da);
    sfc = cairo_xlib_surface_create(d, da, DefaultVisual(d, screen), *x, *y);
    return sfc;
}
struct Drawer {
    Drawer() {
        d = XOpenDisplay(NULL);
        if (d == NULL) {
            fprintf(stderr, "Failed to open displayn");
            exit(-1);
        }
        // create a new cairo surface in an x11 window as well as a cairo_t* to
        // draw on the x11 window with.
        int x=500, y=500;
        surface = create_x11_surface(d, &x, &y);
        cr = cairo_create(surface);
    }
    // https://stackoverflow.com/a/19308254/2725810
    ~Drawer() {
        cairo_destroy(cr);
        cairo_surface_destroy(surface);
        XCloseDisplay(d);
    }
    // Returns true if need to continue or false if quiting
    bool processEvents() {
        XEvent e;
        if (XPending(cairo_xlib_surface_get_display(surface))) {
            XNextEvent(cairo_xlib_surface_get_display(surface), &e);
            switch (e.type) {
            case ButtonPress:
                drag_start_x = e.xbutton.x;
                drag_start_y = e.xbutton.y;
                break;
            case ButtonRelease:
                last_delta_x = 0;
                last_delta_y = 0;
                break;
            case MotionNotify:
                // http://cairographics.org/manual/cairo-Transformations.html#cairo-translate
                cairo_translate(cr, e.xmotion.x - drag_start_x - last_delta_x,
                                e.xmotion.y - drag_start_y - last_delta_y);
                last_delta_x = e.xmotion.x - drag_start_x;
                last_delta_y = e.xmotion.y - drag_start_y;
                break;
            case ConfigureNotify:
                cairo_xlib_surface_set_size(surface, e.xconfigure.width,
                                            e.xconfigure.height);
                break;
            case ClientMessage:
                return false;
            default:
                fprintf(stderr, "Dropping unhandled XEevent.type = %d.n",
                        e.type);
            }
        }
        return true;
    }
    void draw() {
        cairo_push_group(cr);
        // Clear the background
        cairo_set_source_rgb(cr, 0, 0, 0);
        cairo_paint(cr);
        cairo_set_source_rgb(cr, 0, 1, 0);
        cairo_move_to(cr, 0, 0);
        cairo_line_to(cr, 256, 256);
        cairo_move_to(cr, 256, 0);
        cairo_line_to(cr, 0, 256);
        cairo_set_line_width(cr, 10.0);
        cairo_stroke(cr);
        cairo_pop_group_to_source(cr);
        cairo_paint(cr);
        cairo_surface_flush(surface);
        XFlush(d);
    }
    void run() {
        while (1) {
            if (!processEvents()) break;
            draw();
            sleep(0.1);
        }
    }
private:
    Display *d;
    cairo_surface_t* surface;
    cairo_t* cr;
    int last_delta_x = 0, last_delta_y = 0;
    int drag_start_x, drag_start_y;
};
int main() {
    Drawer d;
    d.run();
    return 0;
}

TL;DR:我没有看到任何泄漏。

这是我的valgrind输出版本(带有cairo和pixman的调试版本(意思是"带符号");(哦,我还加了一个呼叫到cairo_debug_reset_static_data()):

==4035== HEAP SUMMARY:
==4035==     in use at exit: 86,640 bytes in 9 blocks
==4035==   total heap usage: 6,736 allocs, 6,727 frees, 6,728,014 bytes allocated
==4035== 
==4035== 128 bytes in 1 blocks are still reachable in loss record 1 of 9
==4035==    at 0x4C28C4F: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==4035==    by 0x4EA6044: cairo_pattern_create_for_surface (cairo-pattern.c:739)
==4035==    by 0x4E6507F: _cairo_default_context_pop_group (cairo-default-context.c:238)
==4035==    by 0x4E59E10: cairo_pop_group (cairo.c:554)
==4035==    by 0x4E59E10: cairo_pop_group_to_source (cairo.c:594)
==4035==    by 0x4017E0: Drawer::draw() (test.cpp:120)
==4035==    by 0x40183E: Drawer::run() (test.cpp:129)
==4035==    by 0x4013C6: main (test.cpp:144)
==4035== 
==4035== 1,424 bytes in 1 blocks are still reachable in loss record 2 of 9
==4035==    at 0x4C28C4F: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==4035==    by 0x4E65D0B: _cairo_default_context_create (cairo-default-context.c:1463)
==4035==    by 0x4014B8: Drawer::Drawer() (test.cpp:59)
==4035==    by 0x4013BA: main (test.cpp:143)
==4035== 
==4035== 2,064 bytes in 1 blocks are still reachable in loss record 3 of 9
==4035==    at 0x4C28C4F: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==4035==    by 0x636E8AA: _pixman_implementation_create (pixman-implementation.c:38)
==4035==    by 0x636D3EE: _pixman_implementation_create_general (pixman-general.c:250)
==4035==    by 0x636EF45: _pixman_choose_implementation (pixman-implementation.c:388)
==4035==    by 0x63262C8: pixman_constructor (pixman.c:39)
==4035==    by 0x400EA09: call_init.part.0 (dl-init.c:78)
==4035==    by 0x400EAF2: call_init (dl-init.c:36)
==4035==    by 0x400EAF2: _dl_init (dl-init.c:126)
==4035==    by 0x40011C9: ??? (in /lib/x86_64-linux-gnu/ld-2.19.so)
==4035== 
==4035== 2,064 bytes in 1 blocks are still reachable in loss record 4 of 9
==4035==    at 0x4C28C4F: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==4035==    by 0x636E8AA: _pixman_implementation_create (pixman-implementation.c:38)
==4035==    by 0x636BF3F: _pixman_implementation_create_fast_path (pixman-fast-path.c:3286)
==4035==    by 0x636EF60: _pixman_choose_implementation (pixman-implementation.c:391)
==4035==    by 0x63262C8: pixman_constructor (pixman.c:39)
==4035==    by 0x400EA09: call_init.part.0 (dl-init.c:78)
==4035==    by 0x400EAF2: call_init (dl-init.c:36)
==4035==    by 0x400EAF2: _dl_init (dl-init.c:126)
==4035==    by 0x40011C9: ??? (in /lib/x86_64-linux-gnu/ld-2.19.so)
==4035== 
==4035== 2,064 bytes in 1 blocks are still reachable in loss record 5 of 9
==4035==    at 0x4C28C4F: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==4035==    by 0x636E8AA: _pixman_implementation_create (pixman-implementation.c:38)
==4035==    by 0x63871DF: _pixman_implementation_create_mmx (pixman-mmx.c:4021)
==4035==    by 0x63543C5: _pixman_x86_get_implementations (pixman-x86.c:234)
==4035==    by 0x636EF6B: _pixman_choose_implementation (pixman-implementation.c:393)
==4035==    by 0x63262C8: pixman_constructor (pixman.c:39)
==4035==    by 0x400EA09: call_init.part.0 (dl-init.c:78)
==4035==    by 0x400EAF2: call_init (dl-init.c:36)
==4035==    by 0x400EAF2: _dl_init (dl-init.c:126)
==4035==    by 0x40011C9: ??? (in /lib/x86_64-linux-gnu/ld-2.19.so)
==4035== 
==4035== 2,064 bytes in 1 blocks are still reachable in loss record 6 of 9
==4035==    at 0x4C28C4F: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==4035==    by 0x636E8AA: _pixman_implementation_create (pixman-implementation.c:38)
==4035==    by 0x63A82BF: _pixman_implementation_create_sse2 (pixman-sse2.c:6487)
==4035==    by 0x63543A5: _pixman_x86_get_implementations (pixman-x86.c:239)
==4035==    by 0x636EF6B: _pixman_choose_implementation (pixman-implementation.c:393)
==4035==    by 0x63262C8: pixman_constructor (pixman.c:39)
==4035==    by 0x400EA09: call_init.part.0 (dl-init.c:78)
==4035==    by 0x400EAF2: call_init (dl-init.c:36)
==4035==    by 0x400EAF2: _dl_init (dl-init.c:126)
==4035==    by 0x40011C9: ??? (in /lib/x86_64-linux-gnu/ld-2.19.so)
==4035== 
==4035== 2,064 bytes in 1 blocks are still reachable in loss record 7 of 9
==4035==    at 0x4C28C4F: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==4035==    by 0x636E8AA: _pixman_implementation_create (pixman-implementation.c:38)
==4035==    by 0x63A895F: _pixman_implementation_create_ssse3 (pixman-ssse3.c:345)
==4035==    by 0x636EF6B: _pixman_choose_implementation (pixman-implementation.c:393)
==4035==    by 0x63262C8: pixman_constructor (pixman.c:39)
==4035==    by 0x400EA09: call_init.part.0 (dl-init.c:78)
==4035==    by 0x400EAF2: call_init (dl-init.c:36)
==4035==    by 0x400EAF2: _dl_init (dl-init.c:126)
==4035==    by 0x40011C9: ??? (in /lib/x86_64-linux-gnu/ld-2.19.so)
==4035== 
==4035== 2,064 bytes in 1 blocks are still reachable in loss record 8 of 9
==4035==    at 0x4C28C4F: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==4035==    by 0x636E8AA: _pixman_implementation_create (pixman-implementation.c:38)
==4035==    by 0x63714CF: _pixman_implementation_create_noop (pixman-noop.c:155)
==4035==    by 0x63262C8: pixman_constructor (pixman.c:39)
==4035==    by 0x400EA09: call_init.part.0 (dl-init.c:78)
==4035==    by 0x400EAF2: call_init (dl-init.c:36)
==4035==    by 0x400EAF2: _dl_init (dl-init.c:126)
==4035==    by 0x40011C9: ??? (in /lib/x86_64-linux-gnu/ld-2.19.so)
==4035== 
==4035== 72,704 bytes in 1 blocks are still reachable in loss record 9 of 9
==4035==    at 0x4C28C4F: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==4035==    by 0x554E11F: ??? (in /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.21)
==4035==    by 0x400EA09: call_init.part.0 (dl-init.c:78)
==4035==    by 0x400EAF2: call_init (dl-init.c:36)
==4035==    by 0x400EAF2: _dl_init (dl-init.c:126)
==4035==    by 0x40011C9: ??? (in /lib/x86_64-linux-gnu/ld-2.19.so)
==4035== 
==4035== LEAK SUMMARY:
==4035==    definitely lost: 0 bytes in 0 blocks
==4035==    indirectly lost: 0 bytes in 0 blocks
==4035==      possibly lost: 0 bytes in 0 blocks
==4035==    still reachable: 86,640 bytes in 9 blocks
==4035==         suppressed: 0 bytes in 0 blocks
==4035== 
==4035== For counts of detected and suppressed errors, rerun with: -v
==4035== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)

不知道libstdc++中的泄漏,但由于_dl_init中存在泄漏,因此应该是无害的(启动期间的一次性"泄漏")。

pixman_constructor也是如此:Pixman根据其运行的CPU使用优化的代码路径。这是一次一次性初始化,用于分配无法释放的内存。这是无害的。

这只留下两个漏洞。cairo_pop_group_to_source()中内部分配的模式没有释放,但cairo_create()创建的cairo上下文也没有释放。发生这些泄漏是因为我错误地调用了cairo_debug_reset_static_data()。我在main中调用了这个函数,也就是在析构函数运行之前。把它移到析构函数会使泄漏消失。。。很抱歉之前没有注意到这一点,也很抱歉懒得更新以上内容。

因此,对我来说,有一个来自pixman的预期泄漏和一个来自libstdc++的意外泄漏。两者都和开罗没有关系。为此,我使用了cairo版本1.14.2-95-g98d01cd。