【问题标题】:Cairo memory leak on draw开罗绘图时内存泄漏
【发布时间】:2013-05-29 18:24:43
【问题描述】:

我在下面编写了一个 drawCircle 函数,但是随着更多的圆圈被绘制/重绘,内存使用量大大增加,所以我假设某处存在内存泄漏,但我似乎无法弄清楚。我尝试在函数末尾删除实例,但这没有帮助。

void drawCircle(cairo_surface_t *container, int x, int y, int radius, float r, float g, float b, float a)
{   
cairo_t *cairoInstance;                                                                                                                      
cairoInstance = cairo_create(container);                                                                                                                     

cairo_set_source_rgba(cairoInstance, r, g, b, a);
cairo_arc(cairoInstance, x, y, radius, 0, 2*M_PI);
cairo_stroke_preserve(cairoInstance);
cairo_fill_preserve(cairoInstance);

//delete cairoInstance;
gtk_widget_queue_draw_area(GTK_WIDGET(frame2), 0, 0, WINDOW_WIDTH, WINDOW_HEIGHT);   
}

有什么想法吗? 提前致谢。

【问题讨论】:

  • 使用 valgrind 确定内存泄漏的根源

标签: c++ memory memory-leaks cairo


【解决方案1】:

几点:

  • cairo_ts 被引用计数。完成cairo_t* 后,请致电cairo_destroy。或者,您不需要为每个圈子创建和销毁 cairo_t - 通过拉出对 cairo_create 的调用来重构函数。
  • 除非您需要它们,否则首选 cairo_X 函数而不是 cairo_X_preserve 函数。在你的代码中cairo_fill_preserve 应该是cairo_preserve。 (但应该保留笔画,以便下面的填充工作。)
  • 使用gtk_widget_queue_draw_area 使您的 gtk 小部件的矩形无效的调用也可以被重构出来,并且每次绘制只执行一次。
  • gtk_widget_queue_draw_area 使小部件窗口的矩形区域无效-您可能只使用gdk_window_invalidate_rect 就可以了-请参阅the documentation

重构后的伪代码(使用假设的 Circle 类型):

void drawCircle(cairo_t *cr, int x, int y, int radius, float r, float g, float b, float a) {   
    cairo_set_source_rgba(cr, r, g, b, a);
    cairo_arc(cr, x, y, radius, 0, 2*M_PI);
    cairo_stroke_preserve(cr); // keep the arc so that we can call cairo_fill
    cairo_fill(cr);
}

void functionThatDrawsCircles(cairo_surface_t* surface, Circle* circles, int num) {
    cairo_t* cr = cairo_create(surface);
    for(int i = 0; i < num; i++) {
        drawCircle(cr, circles[i].x, circles[i].y, 10, circles[i].r, circles[i].g, circles[i].b, 1.0);
    }
    cairo_destroy(cr);
    gtk_widget_queue_draw_area(GTK_WIDGET(frame2), 0, 0, WINDOW_WIDTH, WINDOW_HEIGHT);   
}

【讨论】:

  • 之前试过了,好像没有效果。
  • 你可能也应该调用cairo_fill而不是cairo_fill_preserve,除非你在调用drawCircle之后需要那个圆弧路径。此外,gtk_widget_queue_draw_area 每次调用都会消耗内存,直到主循环空闲,所以如果您可能不想在 drawCircle 中创建无效矩形(将其移到外面,并且每帧/更新仅调用一次等)跨度>
  • 这样做了,我认为它可以节省一些内存,但是在重绘 15 次后程序是否应该使用 500+ MB 的 RAM?
  • 好的,所以经过进一步测试,结果是 gtk_widget_queue_draw_area(GTK_WIDGET(frame2), 0, 0, WINDOW_WIDTH, WINDOW_HEIGHT);占用了很多内存。我已经用 gtk_widget_queue_draw_area 替换了它,它仍然需要很多但没有那么多。我想知道为什么它会占用这么多内存而不是在重绘后释放它。
  • 我已更新我的答案以包含来自这些 cmets 的更多信息。抱歉,您用哪个函数替换了它? (您说了两次 gtk_widget_queue_draw_area..)可能导致内存使用量猛增的一种方法是,如果您在循环中多次(超过 15 次)调用该函数而不让 gtk 应用程序进入空闲状态。如果您在循环中运行绘图函数以尝试查看内存增长/“泄漏”,这可能就是它。尝试使用 valgrind 找出泄漏的确切内容。
猜你喜欢
  • 2016-10-19
  • 2011-09-19
  • 1970-01-01
  • 1970-01-01
  • 2011-10-22
  • 1970-01-01
  • 2015-09-15
  • 2022-01-10
相关资源
最近更新 更多