1

我在目前正在 MacOSX 上编译的试驾应用程序中使用 Pango 库和 Cairo,没有 GTK。我有一个内存泄漏问题,我已经追踪到这个函数:

void draw_with_cairo (void)
{
    PangoLayout *layout;
    PangoFontDescription *desc;
    int i;

    cairo_save (cr);
    cairo_scale (cr, 1, -1);
    cairo_translate (cr, 0, -HEIGHT);

    cairo_translate (cr, 400, 300);

    layout = pango_cairo_create_layout (cr);

    pango_layout_set_text (layout, "Test", -1);
    desc = pango_font_description_from_string ("‌BMitra 32");
    pango_layout_set_font_description (layout, desc);
    pango_font_description_free (desc);

    for (i = 0; i < 12; i++)
    {
        int width, height;
        double angle = iter + (360.0 * i) / 12;
        double red;

        cairo_save (cr);

        red   = (1 + cos ((angle - 60) * G_PI / 180.)) / 2;
        cairo_set_source_rgb (cr, red, 0, 1.0 - red);

        cairo_rotate (cr, angle * G_PI / 180.);

        pango_cairo_update_layout (cr, layout);

        pango_layout_get_size (layout, &width, &height);
        cairo_move_to (cr, - ((double)width / PANGO_SCALE) / 2, - 250);
        pango_cairo_show_layout (cr, layout);

        cairo_restore (cr);
    }

    cairo_restore (cr);
    g_object_unref (layout);

}

这个例程被调用了很多次,可能在一秒钟内被调用了一百次。并且内存泄漏很大,3 秒内大约 30MB,并且具有恒定的速率。当我比较这段代码时,对我来说似乎很好。我已经搜索过这个,在 Gtk 应用程序中使用 pango 时发现了许多关于内存泄漏的引用,并且他们都在 pango 或 gtk 中寻找补丁。我真的很困惑,不敢相信在像 pango 这样的大量使用的库中会有这样的错误,并认为这是我自己的代码的问题。任何建议表示赞赏。

这是 Uli 代码的 vmmap 结果:

Executing vmmap -resident 25897 | grep TOTAL at beginning of main()
TOTAL                            321.3M   126.2M      485 
TOTAL                              18.0M       200K       1323       173K      0%       2
Executing vmmap -resident 25897 | grep TOTAL after cairo init
TOTAL                            331.3M   126.4M      489 
TOTAL                              27.0M       224K       1327      1155K      4%       6
Executing vmmap -resident 25897 | grep TOTAL after one iteration
TOTAL                            383.2M   143.9M      517 
TOTAL                              37.2M      3368K      18634      3423K      8%       5
Executing vmmap -resident 25897 | grep TOTAL after loop
TOTAL                            481.6M   244.1M      514 
TOTAL                             137.2M     103.7M     151961      66.4M     48%       6
Executing vmmap -resident 25897 | grep TOTAL at end
TOTAL                            481.6M   244.1M      520 
TOTAL                             136.3M     103.1M     151956      65.4M     48%      11

这是最后阶段的未过滤输出:

Executing vmmap -resident 25751 at end
Process:         main [25751]
Path:            /PATH/OMITTED/main
Load Address:    0x109b9c000
Identifier:      main
Version:         ???
Code Type:       X86-64
Parent Process:  bash [837]

Date/Time:       2016-01-30 23:28:35.866 +0330
Launch Time:     2016-01-30 23:27:35.148 +0330
OS Version:      Mac OS X 10.11.2 (15C50)
Report Version:  7
Analysis Tool:   /Applications/Xcode.app/Contents/Developer/usr/bin/vmmap
Analysis Tool Version:  Xcode 7.0.1 (7A1001)
----

Virtual Memory Map of process 25751 (main)
Output report format:  2.4  -- 64-bit process
VM page size:  4096 bytes

==== Non-writable regions for process 25751

==== Legend
SM=sharing mode:  
    COW=copy_on_write PRV=private NUL=empty ALI=aliased 
    SHM=shared ZER=zero_filled S/A=shared_alias

==== Summary for process 25751
ReadOnly portion of Libraries: Total=219.6M resident=112.2M(51%) swapped_out_or_unallocated=107.5M(49%)
Writable regions: Total=155.7M written=5448K(3%) resident=104.1M(67%) swapped_out=0K(0%) unallocated=51.6M(33%)

                                VIRTUAL RESIDENT   REGION 
REGION TYPE                        SIZE     SIZE    COUNT (non-coalesced) 
===========                     ======= ========  ======= 
Activity Tracing                  2048K      12K        2 
Dispatch continuations            8192K      32K        2 
Kernel Alloc Once                    8K       8K        3 
MALLOC guard page                   32K       0K        7 
MALLOC metadata                    364K      84K       11 
MALLOC_LARGE                       260K     260K        2         see MALLOC ZONE table below
MALLOC_LARGE (empty)               980K     668K        2         see MALLOC ZONE table below
MALLOC_LARGE metadata                4K       4K        2         see MALLOC ZONE table below
MALLOC_SMALL                      32.0M     880K        3         see MALLOC ZONE table below
MALLOC_TINY                      104.0M   102.1M        7         see MALLOC ZONE table below
STACK GUARD                       56.0M       0K        3 
Stack                             8264K      60K        3 
VM_ALLOCATE                         16K       8K        2 
__DATA                            16.7M    13.6M      217 
__IMAGE                            528K     104K        2 
__LINKEDIT                        92.4M    22.5M       34 
__TEXT                           127.2M    89.6M      220 
__UNICODE                          552K     476K        2 
mapped file                       32.2M    13.7M        4 
shared memory                      328K     172K       10 
===========                     ======= ========  ======= 
TOTAL                            481.6M   244.3M      518 

                                 VIRTUAL   RESIDENT ALLOCATION      BYTES          REGION
MALLOC ZONE                         SIZE       SIZE      COUNT  ALLOCATED  % FULL   COUNT
===========                      =======  =========  =========  =========  ======  ======
DefaultMallocZone_0x109bd0000     136.3M     103.2M     151952      65.4M     48%      10
GFXMallocZone_0x109bd3000             0K         0K          0         0K               0
===========                      =======  =========  =========  =========  ======  ======
TOTAL                             136.3M     103.2M     151952      65.4M     48%      10

我省略了不可写区域部分,因为它溢出了 stackoverflow 限制!

4

1 回答 1

1

我没有看到任何内存泄漏。以下程序在运行上述函数 100.000 次之前和之后打印其内存使用情况。这两个数字对我来说都是一样的。

#include <cairo.h>
#include <math.h>
#include <pango/pangocairo.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

#define HEIGHT 500
#define WIDTH 500

void draw_with_cairo (cairo_t *cr)
{
    PangoLayout *layout;
    PangoFontDescription *desc;
    int i;

    cairo_save (cr);
    cairo_scale (cr, 1, -1);
    cairo_translate (cr, 0, -HEIGHT);

    cairo_translate (cr, 400, 300);

    layout = pango_cairo_create_layout (cr);

    pango_layout_set_text (layout, "Test", -1);
    desc = pango_font_description_from_string ("‌BMitra 32");
    pango_layout_set_font_description (layout, desc);
    pango_font_description_free (desc);

    for (i = 0; i < 12; i++)
    {
        int width, height;
        double angle = i + (360.0 * i) / 12;
        double red;

        cairo_save (cr);

        red   = (1 + cos ((angle - 60) * G_PI / 180.)) / 2;
        cairo_set_source_rgb (cr, red, 0, 1.0 - red);

        cairo_rotate (cr, angle * G_PI / 180.);

        pango_cairo_update_layout (cr, layout);

        pango_layout_get_size (layout, &width, &height);
        cairo_move_to (cr, - ((double)width / PANGO_SCALE) / 2, - 250);
        pango_cairo_show_layout (cr, layout);

        cairo_restore (cr);
    }

    cairo_restore (cr);
    g_object_unref (layout);
}

static void print_memory_usage(const char *comment)
{
    char buffer[1024];
    sprintf(buffer, "grep -E VmPeak\\|VmSize /proc/%d/status", getpid());
    printf("Executing %s %s\n", buffer, comment);
    system(buffer);
}

int main()
{
    cairo_surface_t *s;
    cairo_t *cr;
    int i;

    print_memory_usage("at beginning of main()");

    s = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, WIDTH, HEIGHT);
    cr = cairo_create(s);

    print_memory_usage("after cairo init");

    draw_with_cairo(cr);
    print_memory_usage("after one iteration");

    for (i = 0; i < 100 * 1000; i++)
        draw_with_cairo(cr);

    print_memory_usage("after loop");

    cairo_surface_destroy(s);
    cairo_destroy(cr);

    print_memory_usage("at end");
    return 0;
}

我的输出(没有任何内存泄漏的痕迹):

Executing grep -E VmPeak\|VmSize /proc/31881/status at beginning of main()
VmPeak:    76660 kB
VmSize:    76660 kB
Executing grep -E VmPeak\|VmSize /proc/31881/status after cairo init
VmPeak:    77640 kB
VmSize:    77640 kB
Executing grep -E VmPeak\|VmSize /proc/31881/status after one iteration
VmPeak:    79520 kB
VmSize:    79520 kB
Executing grep -E VmPeak\|VmSize /proc/31881/status after loop
VmPeak:    79520 kB
VmSize:    79520 kB
Executing grep -E VmPeak\|VmSize /proc/31881/status at end
VmPeak:    79520 kB
VmSize:    78540 kB

PS:我在最新的 debian 测试 amd64 上对此进行了测试。

于 2016-01-29T18:12:59.860 回答