使用 awtk fb 项目与 valgrind 检测基于 awtk 开发的 gui 程序中的内存泄露问题

awtk-linux-fb 项目

awtk-linux-fb 项目是 awtk 针对 arm linux 平台的移植。这个项目的绘制通过读写 linux 中的 framebuffer 图形设备文件来完成,鼠标与键盘事件通过独立的两个线程来检测并投递到 gui 中。更详细的信息请访问 awtk-linux-fb project。

为什么要编这个东东

在开发基于 awtk 的 gui 程序时有时会遇到程序跑一段时间后异常的问题,这样的问题很多都是由于内存泄露所致。关于内存泄露可以使用很多工具来进行定位,在 linux 上经常使用的要数 valgrind 了。

awtk 有基于 linux pc 端的移植,这个移植依赖了很多三方的库函数,这些依赖不利于使用 valgrind 来定位问题。而 awtk-linux-fb 项目却没有这样的问题。它没有依赖太多的三方库,它使用了标准的图形界面接口 framebuffer 来完成绘制工作,同时鼠标与键盘事件的检测与处理也是通过直接检测鼠标与键盘的设备文件完成的。在这种实现的基础上使用 valgrind 来检测内存泄露,能更加专注于上层用户程序的问题,这也是我的目标。

下载相关项目源码并编译

具体的步骤请参考 AWTK针对arm-linux平台的移植。

由于我编译的是主机版的 awtk-linux-fb 项目,我只需要修改 awtk_config.py 文件中的相关配置然后按照官方文档进行编译即可。我这里只只用官方的 demo 进行示例,读者可以将官方 demo 替换为自己开发的 gui 程序。

在虚拟机中运行

awtk-linux-fb 项目编译出的 gui 程序不能直接运行,首先要关闭 X window 并且切换到 vga console mode,更进一步的信息请访问 The Framebuffer Console

如果你使用的是桌面版 linux,那么你可能需要修改 grub 中的引导参数。关键的步骤如下:

  1. 修改 grub 配置,添加 gfxmode 1920x1080 此行
  2. 内核启动参数添加 vga=791 3

我在网上搜索了很多帖子,最终却发现在我的主机上并不需要进行额外的配置,同时我在虚拟机中也进行了测试,它完全不需要任何配置即可完成。

基于这样的尝试经历,我建议你使用虚拟机, 它至少有两个好处:

  1. 不需要修改引导参数,这与虚拟机的实现机制有关,是实际测试的结果。
  2. 可以 ssh 到虚拟机中以避免终端输出影响显示。使用 framebuffer 的程序其显示都是通过对 framebuffer 的写完成的。无论图形还是终端文字输出,它们都共用了一个 framebuffer。这样当在终端中执行图形化程序时,终端输出的信息将会影响程序的正常显示。

关键的步骤如下:

  1. 在主机上编译生成可执行程序,这里以 demoui 为例
  2. 通过 scp 将可执行程序与资源文件复制到虚拟机中
  3. 关闭虚拟机的 X window ——执行 sudo init 3 即可完成
  4. 通过 ssh 登录到虚拟机中,执行程序。

第一次尝试时我遇到了下面的问题i:

Print keyboard: : Permission denied input_dispatch_one_event:71 mouse
read failed(ret=-1, errno=13, fd=-1, filename=/dev/input/mice) Print
mouse: : Permission denied

从输出信息来看应该是权限不足,我使用 sudo 临时以 root 权限来运行就正常了。

效果图如下:
tty 中运行 demoui

解决无法在 tty 中使用鼠标的问题

tty 中显示出图形界面之后,我发现了一个新的问题——我不能使用鼠标在 tty 中进行点击。这意味着我将无法切换页面,点击按钮以测试事件。经过搜索我发现可以安装 gpm 程序来让鼠标能够在 tty 下使用。

需要执行的步骤如下:

  1. sudo apt-get install gpm
  2. sudo service gpm start

第一个命令在系统中安装 gpm 组件,第二个命令启动 gpm 服务。这之后就可以在 tty 中使用鼠标进行点击了。

效果图如下:
在这里插入图片描述

使用 valgrind 进行内存泄露检查

执行 sudo valgrind --tool=memcheck --leak-check=yes ./release/bin/demoui 命令然后点击控件,最后正常退出程序。ssh 的终端输出中就是我们需要的信息。

终端的部分输出内容如下:

longyu@longyu-pc:~/awtk-linux-fb$ sudo valgrind --tool=memcheck --leak-check=yes ./release/bin/demoui 
==2366== Memcheck, a memory error detector
==2366== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al.
==2366== Using Valgrind-3.14.0 and LibVEX; rerun with -h for copyright info
==2366== Command: ./release/bin/demoui
==2366== 
app_root_is_valid:43 app_root != NULL
try /home/longyu/awtk-linux-fb
try /home/longyu/awtk-linux-fb/release/bin
app_root=/home/longyu/awtk-linux-fb/release
fb_info_t: /dev/fb0
fb_info_t: xres=1024 yres=768 bits_per_pixel=32 mem_size=3145728
fb_info_t: red(16 8) green(8 8) blue(0 8)
line_length=4096 mem_size=3145728 smem_len=3145728
xres_virtual =1024 yres_virtual=768 xpanstep=1 ywrapstep=0
ratio=1.000000 1024 768
Build at: Oct 16 2019 10:54:08
window preload open
window system_bar open
main
==2366== Conditional jump or move depends on uninitialised value(s)
==2366==    at 0x1E95AF: int agge::clipping<int>(int, int, agge::rect<int> const&) (clipper.h:59)
==2366==    by 0x1E64F4: agge::clipper<int>::set(agge::rect<int> const&) (clipper.h:76)
==2366==    by 0x1E550B: agge::rasterizer<agge::clipper<int>, agge::scaling<int> >::set_clipping(agge::rect<float> const&) (rasterizer.h:87)
==2366==    by 0x1E3E95: prepareRasterizer(AGGENVGcontext*, NVGscissor*, NVGpaint*) (nanovg_agge.cpp:235)
==2366==    by 0x1E595D: void renderFill<agge::pixel32_bgra>(void*, NVGpaint*, NVGcompositeOperationState, NVGscissor*, float, float const*, NVGpath const*, int) (nanovg_agge.cpp:333)
==2366==    by 0x2155E4: nvgFill (nanovg.c:2464)
==2366==    by 0x1B2DBE: vgcanvas_nanovg_fill (vgcanvas_nanovg.inc:187)
==2366==    by 0x16A71A: vgcanvas_fill (vgcanvas.c:92)
==2366==    by 0x130480: slide_indicator_fill_dot (slide_indicator.c:202)
==2366==    by 0x1306EA: slide_indicator_default_paint_active_indicator (slide_indicator.c:253)
==2366==    by 0x130852: slide_indicator_paint_one (slide_indicator.c:273)
==2366==    by 0x1310F1: slide_indicator_paint_linear (slide_indicator.c:364)
==2366== 
==2366== Conditional jump or move depends on uninitialised value(s)
==2366==    at 0x1F8F99: int agge::clipping_y<int>(int, agge::rect<int> const&) (clipper.h:55)
==2366==    by 0x1E95E1: int agge::clipping<int>(int, int, agge::rect<int> const&) (clipper.h:59)
==2366==    by 0x1E64F4: agge::clipper<int>::set(agge::rect<int> const&) (clipper.h:76)
==2366==    by 0x1E550B: agge::rasterizer<agge::clipper<int>, agge::scaling<int> >::set_clipping(agge::rect<float> const&) (rasterizer.h:87)
==2366==    by 0x1E3E95: prepareRasterizer(AGGENVGcontext*, NVGscissor*, NVGpaint*) (nanovg_agge.cpp:235)
==2366==    by 0x1E595D: void renderFill<agge::pixel32_bgra>(void*, NVGpaint*, NVGcompositeOperationState, NVGscissor*, float, float const*, NVGpath const*, int) (nanovg_agge.cpp:333)
==2366==    by 0x2155E4: nvgFill (nanovg.c:2464)
==2366==    by 0x1B2DBE: vgcanvas_nanovg_fill (vgcanvas_nanovg.inc:187)
==2366==    by 0x16A71A: vgcanvas_fill (vgcanvas.c:92)
==2366==    by 0x130480: slide_indicator_fill_dot (slide_indicator.c:202)
==2366==    by 0x1306EA: slide_indicator_default_paint_active_indicator (slide_indicator.c:253)
==2366==    by 0x130852: slide_indicator_paint_one (slide_indicator.c:273)
==2366== 
==2366== Conditional jump or move depends on uninitialised value(s)
==2366==    at 0x1F8FB1: int agge::clipping_y<int>(int, agge::rect<int> const&) (clipper.h:55)
==2366==    by 0x1E95E1: int agge::clipping<int>(int, int, agge::rect<int> const&) (clipper.h:59)
==2366==    by 0x1E64F4: agge::clipper<int>::set(agge::rect<int> const&) (clipper.h:76)
==2366==    by 0x1E550B: agge::rasterizer<agge::clipper<int>, agge::scaling<int> >::set_clipping(agge::rect<float> const&) (rasterizer.h:87)
==2366==    by 0x1E3E95: prepareRasterizer(AGGENVGcontext*, NVGscissor*, NVGpaint*) (nanovg_agge.cpp:235)
==2366==    by 0x1E595D: void renderFill<agge::pixel32_bgra>(void*, NVGpaint*, NVGcompositeOperationState, NVGscissor*, float, float const*, NVGpath const*, int) (nanovg_agge.cpp:333)
==2366==    by 0x2155E4: nvgFill (nanovg.c:2464)
==2366==    by 0x1B2DBE: vgcanvas_nanovg_fill (vgcanvas_nanovg.inc:187)
==2366==    by 0x16A71A: vgcanvas_fill (vgcanvas.c:92)
==2366==    by 0x130480: slide_indicator_fill_dot (slide_indicator.c:202)
==2366==    by 0x1306EA: slide_indicator_default_paint_active_indicator (slide_indicator.c:253)
==2366==    by 0x130852: slide_indicator_paint_one (slide_indicator.c:273)
==2366== 
ignore_user_input
window main open
window preload close
main
main
mouse pointer down:0 0
mouse pointer up:0 1
mouse pointer down:0 1
mouse pointer up:0 0
mouse pointer down:0 0
mouse pointer up:127 0
mouse pointer down:73 52
mouse pointer up:73 52
ignore_user_input
animating ignore input
animating ignore input
main to_background
window basic open
basic
mouse pointer down:349 93
mouse pointer up:350 88
mouse pointer down:350 88
mouse pointer up:350 88
ignore_user_input
animating ignore input
animating ignore input
mouse pointer down:350 88
mouse pointer up:417 109
animating ignore input
animating ignore input
main
main to_foreground
mouse pointer down:569 142
mouse pointer up:540 134
mouse pointer down:540 134
mouse pointer up:540 134
mouse pointer down:540 134
mouse pointer up:667 141
mouse pointer down:712 141
mouse pointer up:738 265
==2366== Invalid read of size 2
==2366==    at 0x164823: text_edit_layout_for_stb (text_edit.c:396)
==2366==    by 0x16563A: stb_textedit_click (stb_textedit.h:457)
==2366==    by 0x167ED1: text_edit_click (text_edit.c:785)
==2366==    by 0x13F485: edit_on_event (edit.c:473)
==2366==    by 0x16EC0C: widget_dispatch (widget.c:845)
==2366==    by 0x172724: widget_on_pointer_down_after_children (widget.c:1780)
==2366==    by 0x172863: widget_on_pointer_down_impl (widget.c:1796)
==2366==    by 0x1728E5: widget_on_pointer_down (widget.c:1806)
==2366==    by 0x1726F2: widget_on_pointer_down_children (widget.c:1771)
==2366==    by 0x172844: widget_on_pointer_down_impl (widget.c:1795)
==2366==    by 0x1728E5: widget_on_pointer_down (widget.c:1806)
==2366==    by 0x1726F2: widget_on_pointer_down_children (widget.c:1771)
==2366==  Address 0x30 is not stack'd, malloc'd or (recently) free'd
==2366== 
==2366== 
==2366== Process terminating with default action of signal 11 (SIGSEGV)
==2366==  Access not within mapped region at address 0x30
==2366==    at 0x164823: text_edit_layout_for_stb (text_edit.c:396)
==2366==    by 0x16563A: stb_textedit_click (stb_textedit.h:457)
==2366==    by 0x167ED1: text_edit_click (text_edit.c:785)
==2366==    by 0x13F485: edit_on_event (edit.c:473)
==2366==    by 0x16EC0C: widget_dispatch (widget.c:845)
==2366==    by 0x172724: widget_on_pointer_down_after_children (widget.c:1780)
==2366==    by 0x172863: widget_on_pointer_down_impl (widget.c:1796)
==2366==    by 0x1728E5: widget_on_pointer_down (widget.c:1806)
==2366==    by 0x1726F2: widget_on_pointer_down_children (widget.c:1771)
==2366==    by 0x172844: widget_on_pointer_down_impl (widget.c:1795)
==2366==    by 0x1728E5: widget_on_pointer_down (widget.c:1806)
==2366==    by 0x1726F2: widget_on_pointer_down_children (widget.c:1771)
==2366==  If you believe this happened as a result of a stack
==2366==  overflow in your program's main thread (unlikely but
==2366==  possible), you can try to increase the size of the
==2366==  main thread stack using the --main-stacksize= flag.
==2366==  The main thread stack size used in this run was 8388608.
==2366== 
==2366== HEAP SUMMARY:
==2366==     in use at exit: 6,690,513 bytes in 1,253 blocks
==2366==   total heap usage: 2,890 allocs, 1,637 frees, 27,965,539 bytes allocated
==2366== 
==2366== 288 bytes in 1 blocks are possibly lost in loss record 291 of 365
==2366==    at 0x4837B65: calloc (vg_replace_malloc.c:752)
==2366==    by 0x40116D1: allocate_dtv (dl-tls.c:286)
==2366==    by 0x401203D: _dl_allocate_tls (dl-tls.c:532)
==2366==    by 0x49F0B95: allocate_stack (allocatestack.c:621)
==2366==    by 0x49F0B95: pthread_create@@GLIBC_2.2.5 (pthread_create.c:669)
==2366==    by 0x1E0837: tk_thread_start (thread.c:94)
==2366==    by 0x149EA5: input_thread_run (input_thread.c:293)
==2366==    by 0x1490F4: main_loop_init (main_loop_linux.c:84)
==2366==    by 0x11813F: tk_init (awtk_global.c:209)
==2366==    by 0x1179E1: main (demo_main.c:71)
==2366== 
==2366== 288 bytes in 1 blocks are possibly lost in loss record 292 of 365
==2366==    at 0x4837B65: calloc (vg_replace_malloc.c:752)
==2366==    by 0x40116D1: allocate_dtv (dl-tls.c:286)
==2366==    by 0x401203D: _dl_allocate_tls (dl-tls.c:532)
==2366==    by 0x49F0B95: allocate_stack (allocatestack.c:621)
==2366==    by 0x49F0B95: pthread_create@@GLIBC_2.2.5 (pthread_create.c:669)
==2366==    by 0x1E0837: tk_thread_start (thread.c:94)
==2366==    by 0x149890: mouse_thread_run (mouse_thread.c:246)
==2366==    by 0x14912E: main_loop_init (main_loop_linux.c:86)
==2366==    by 0x11813F: tk_init (awtk_global.c:209)
==2366==    by 0x1179E1: main (demo_main.c:71)
==2366== 
==2366== LEAK SUMMARY:
==2366==    definitely lost: 0 bytes in 0 blocks
==2366==    indirectly lost: 0 bytes in 0 blocks
==2366==      possibly lost: 576 bytes in 2 blocks
==2366==    still reachable: 6,689,937 bytes in 1,251 blocks
==2366==         suppressed: 0 bytes in 0 blocks
==2366== Reachable blocks (those to which a pointer was found) are not shown.
==2366== To see them, rerun with: --leak-check=full --show-leak-kinds=all

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值