【问题标题】:Memory Leak in PangoPango 内存泄漏
【发布时间】:2016-01-26 05:41:16
【问题描述】:

我在目前正在 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 限制!

【问题讨论】:

  • 你有任何独立的例子来说明我可以尝试的问题吗?
  • 您使用的是哪个 Pango 版本? Google 发现 bugzilla.gnome.org/show_bug.cgi?id=474708 是内存泄漏,显然已在 Pango 1.18.2 中修复。
  • 我刚刚检查过,pango-1.38.1。事实上,它是 macports 中的最新版本。我想这是一个未报告的错误。但在所有这些搜索之后,我对 pango 失去了信任!到处都是关于内存泄漏的报告,在结构良好的代码中不应该出现这种情况。
  • 顺便说一句,我发现内存泄漏发生在 pango_cairo_update_layout 函数中。

标签: memory-leaks cairo pango pangocairo


【解决方案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

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

【讨论】:

  • 所以我猜问题出在mac版本的pango上。我看到了泄漏,它肯定是在那个例程中。事实上,我已经将它指向 pango 布局。
  • 嗯,这是一个棘手的情况,我根本不倾向于修改 pango!
  • 类似上面的内容会重现您的问题吗? (删除 /proc-magic 后,我想用 getrusage() 替换它是有意义的)
  • 首先谢谢你教我!我运行了您的代码,并进行了镜像修改。而不是 /proc-magic (如你所说!),我不得不使用 vmmap 如下:“vmmap -resident %d | grep TOTAL”。我只是对它进行了 grep-ed 以提供总内存使用量。我将结果附加到问题文本中。再次感谢。
猜你喜欢
  • 2012-09-04
  • 1970-01-01
  • 1970-01-01
  • 2011-10-08
  • 2013-01-20
  • 2011-10-31
  • 2019-08-10
  • 2013-06-24
  • 2011-03-22
相关资源
最近更新 更多