使用zig的内存分配器作为awtk的内存分配器后,内存分配器检测出大量的内存泄露!
zig的DebugAllocator内存分配器(以前叫GeneralPurposeAllocator)支持内存泄露检测,并且支持泄露产生位置的堆栈回溯。这个特性对于C的内存管理来说,绝对是神器。于是捣鼓了下让awtk使用zig的内存分配器:
首先在awtk/src/mem.c文件添加用于设置外部内存分配器的接口如下:
ret_t mem_set_allocator(mem_allocator_t* allocator) {
return_value_if_fail(allocator != NULL, RET_BAD_PARAMS);
s_allocator = allocator;
return RET_OK;
}
然后在zig源码上实现mem_allocator,见这里:https://gitee.com/ufbycd/awtk-mvvm-zig-example/blob/dev/src/awtk.zig#L118
然后运行awtk-mvvm-zig-example程序,程序退出后分配器打印了大量内存泄露信息,泄露位置集中在fscript_parser和AWTK-MVVM的data_binding。我分析了一两个位置,确实是内存泄露了,比如这个:
error(gpa): memory address 0x7ecfd3f41780 leaked:
/home/chenss/workspace/zlgopen/awtk-mvvm-zig-example/src/awtk.zig:148:43: 0x12ce088 in alloc (awtk-mvvm-zig-example)
const slice = self.allocator.alloc(u8, @intCast(space)) catch return null;
^
src/tkc/mem_allocator.h:74:10: 0x7ecfd717306a in mem_allocator_alloc (src/tkc/mem.c)
src/tkc/mem.c:165:10: 0x7ecfd7174799 in tk_calloc (src/tkc/mem.c)
src/tkc/fscript.c:354:18: 0x7ecfd7161b46 in func_args_init (src/tkc/fscript.c)
src/tkc/fscript.c:3383:7: 0x7ecfd716d3f1 in fscript_func_call_init_func (src/tkc/fscript.c)
src/tkc/fscript.c:3445:3: 0x7ecfd716d711 in fscript_func_call_create (src/tkc/fscript.c)
src/tkc/fscript.c:2238:18: 0x7ecfd7168eec in fscript_load (src/tkc/fscript.c)
src/tkc/fscript.c:2267:10: 0x7ecfd7169142 in fscript_create_ex (src/tkc/fscript.c)
完整的内存泄露输出信息见附件,完整的zig代码实现在awtk-mvvm-zig-example仓库的dev分支:https://gitee.com/ufbycd/awtk-mvvm-zig-example/blob/dev
我只分析了一两个位置,不太确定是否真的有这么多泄露,建议还是仔细分析下。
已修改,非常感谢。最近的修改导致fscript和binding rule之间引用计数循环引用导致的。需要更新awtk和awtk-mvvm。
已修改,非常感谢。最近的修改导致fscript和binding rule之间引用计数循环引用导致的。需要更新awtk和awtk-mvvm。
拉取最新代码测试,没有内存泄露了。建议awtk添加上述那种设置外部内存分配器的接口。
valgrind是查内存问题的最好工具,内存泄漏、越界访问和未初始化的变量等。内存分配器能做的很有限。
内存检测只是一个方面,主要是方便跟zig交互、统一内存管理。zig有多种不同优化策略的分配器,能同时满足Debug版的稳定、Release版的高效的需求。 这个接口也就一行代码。
valgrind是查内存问题的最好工具,内存泄漏、越界访问和未初始化的变量等。内存分配器能做的很有限。
valgrind真的好用?怎么我试下了发现启动非常慢?
$ time valgrind ./bin/demoui
...
valgrind ./bin/demoui 12.62s user 0.93s system 3% cpu 6:14.91 total
6分多钟才能启动完成,不可能经常启动这东西,用处不大。
启动过程中,它会重新编译,插入指令,是要慢点。也不至于那么慢吧,我10年前买的mac air测试,启动时间20秒,后续运行速度可以接受。
valgrind 太好用了,反正我是离不开,可以说如果没有valgrind,我就不敢用C/C++。以前培训新同事时,我也要求他们必须掌握valgrind的使用方法。
顺便说一下,因为有valgrind,我觉得rust就是坨屎。
可能是系统问题,更新系统之后,valgrind启动快了不少,但仍要10来秒。
相较于zig这边添加内置的内存泄漏检测功能后,基本没有启动开销,体验上还是有差别的。
我个人也觉得rust太复杂了,不太喜欢。至于zig,简而不陋,个人是比较喜欢的。比如它其实已经内置实现了valgrind的所有功能。而它的编译时泛型和反射特性,非常有利于实现声明式UI
valgrind的优点是非侵入,程序不需要做任何修改。
zig 的语法我可以接受,zig 能配合keil一起用吗,很多arm开发板都是用的keil工程。
zig可以编译并导出C ABI的静态库和头文件,keil工程链接这个库并使用这个头文件即可。
新版keil的C编译器其实是clang,zig可以导出符合其ABI的库。