将Vala与C结合使用时会导致内存泄漏
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了将Vala与C结合使用时会导致内存泄漏相关的知识,希望对你有一定的参考价值。
以下Vala代码与C结合导致内存泄漏,我无法绕过它。
Meyinvala
using GLib;
[CCode (cname = "c_function")]
public static extern void c_function (out Tree<int, Tree<int, string>> tree);
public static int main () {
Tree<int, Tree<int, string>> tree;
c_function (out tree);
// If code were to end here and return 0, no memory leak happens, but
// if we call c_function again, memory leak happens according to valgrind
c_function (out tree); // Leak happens on this second call
return 0;
}
main.c中
#include <glib.h>
gint treeCompareFunction (gint a, gint b);
void extern c_function (GTree **tree) {
*tree = g_tree_new ((GCompareFunc)treeCompareFunction);
for (int i = 0; i < 3; i++) {
// Memory leak in the next line when function is called a second time
GTree * nestedTree = g_tree_new ((GCompareFunc)treeCompareFunction);
g_tree_insert (nestedTree, i, "value 1");
g_tree_insert (*tree, i, (gpointer) nestedTree);
}
}
gint treeCompareFunction (gint a, gint b) {
if (a < b) return -1;
if (a == b) return 0;
return 1;
}
我不明白为什么如果我只调用C函数一次没有发生内存泄漏,但如果我第二次调用它,main.c的第10行在for循环中创建一个Tree会导致内存泄漏。
代码编译用
valac Main.vala main.c -g
然后运行
valgrind --leak-check=yes ./Main
我想知道是否有可能解决它。我尝试在第二次调用C函数之前清空Vala代码中的树。没有成功。如果在C函数的第二次调用时它不是NULL,也尝试销毁作为参数传递的树。也没有成功。仍然有内存泄漏。
看看你提供的代码,我会考虑在你的C代码中使用g_tree_new_full ()
而不是g_tree_new ()
。
您正在重新使用tree
作为Vala代码中的out参数。因此,在第二次调用时,应释放分配给tree
的第一个值。我希望Vala生成一个调用来执行此操作,但我没有编写任何示例代码来检查。您可以使用--ccode
开关将您的Vala代码编译为valac
以检查生成的C.
只要Vala调用g_tree_unref ()
,那么你的C代码的设置就不会释放嵌套树。你需要一个GDestroyNotify
函数来嵌套树传递给g_tree_new_full ()
。
更新
错误在您的C代码中。你的C代码应该是:
#include <glib.h>
gint treeCompareFunction (gint a, gint b);
void extern c_function (GTree **tree) {
*tree = g_tree_new_full ((GCompareFunc)treeCompareFunction,
NULL,
NULL,
g_tree_unref
);
for (int i = 0; i < 3; i++) {
GTree * nestedTree = g_tree_new ((GCompareFunc)treeCompareFunction);
g_tree_insert (nestedTree, i, "value 1");
g_tree_insert (*tree, i, (gpointer) nestedTree);
}
}
gint treeCompareFunction (gint a, gint b) {
if (a < b) return -1;
if (a == b) return 0;
return 1;
}
注意使用g_tree_unref
时使用GDestroyNotify
作为g_tree_new_full
函数。
Valgrind泄漏摘要现在报告:
==22035== LEAK SUMMARY:
==22035== definitely lost: 0 bytes in 0 blocks
==22035== indirectly lost: 0 bytes in 0 blocks
==22035== possibly lost: 1,352 bytes in 18 blocks
之前,根据您的问题中的代码,泄漏摘要是:
==21436== LEAK SUMMARY:
==21436== definitely lost: 288 bytes in 6 blocks
==21436== indirectly lost: 240 bytes in 6 blocks
==21436== possibly lost: 1,352 bytes in 18 blocks
找到了解决方案。这绝不是微不足道的,因为它需要查看Vala正在做什么,并查看gtree.c源代码,以了解分配的树内存发生了什么。
因为Vala默认在程序结束时在根树上调用g_tree_unref
,所以根树被释放,但是作为其一部分的嵌套树的内存块将丢失并且不会被释放。一个人必须让Vala在那些嵌套树上调用g_tree_unref
。一种方法是拥有对嵌套树的引用。这可以通过以下方式在根树的foreach TraverseFunc
中完成
Meyinvala
using GLib;
[CCode (cname = "c_function")]
public static extern void c_function (out Tree<int, Tree<int, string>> tree);
public static int main () {
Tree<int, Tree<int, string>> tree;
c_function (out tree);
// Iterate through the tree and get a strong reference to the values
// to free them
tree.@foreach ((TraverseFunc<int, Tree<int, string>>)valueDestroyThroughTraversing);
c_function (out tree);
tree.@foreach ((TraverseFunc<int, Tree<int, string>>)valueDestroyThroughTraversing);
return 0;
}
public bool valueDestroyThroughTraversing (int treeKey, owned Tree<int, string> treeValue) {
// Do something with the keys and values of the tree if desired
// treeValue will go out of scope at the end of the method
// and Vala will free it
return false;
}
main.c中
#include <stdio.h>
#include <glib.h>
gint treeCompareFunction (gint a, gint b);
void extern c_function (GTree **tree) {
*tree = g_tree_new ((GCompareFunc)treeCompareFunction);
for (int i = 0; i < 3; i++) {
GTree * nestedTree = g_tree_new ((GCompareFunc)treeCompareFunction);
g_tree_insert (nestedTree, (gpointer) ((gintptr)i), "value 1");
g_tree_insert (*tree, (gpointer) ((gintptr)i), nestedTree);
}
}
gint treeCompareFunction (gint a, gint b) {
if (a < b) return -1;
if (a == b) return 0;
return 1;
}
以上是关于将Vala与C结合使用时会导致内存泄漏的主要内容,如果未能解决你的问题,请参考以下文章