英文:
Why does this function cause memory leaks?
问题
I'm playing around with libfprint
and I created a really simple function:
#include <libfprint-2/fprint.h>
#include <glib-2.0/glib-unix.h>
void start_device() {
FpContext *ctx = fp_context_new();
fp_context_enumerate(ctx);
}
int main() {
start_device();
}
I'm compiling with gcc using gcc -fsanitize=address
and I'm getting memory leaks and I can't figure out why.
Edit: Output
=================================================================
==55025==ERROR: LeakSanitizer: detected memory leaks
Direct leak of 3 byte(s) in 1 object(s) allocated from:
#0 0x7f14a8aba6af in __interceptor_malloc (/lib64/libasan.so.8+0xba6af)
#1 0x7f14a56d3017 in __vasprintf_internal (/lib64/libc.so.6+0x80017)
#2 0x7af10c9e9cbbccff (<unknown module>)
SUMMARY: AddressSanitizer: 3 byte(s) leaked in 1 allocation(s).
Edit 2: If I delete `fp_context_enumerate(ctx);` I don't get memory leaks, so I guess there's the problem but I don't know why.
<details>
<summary>英文:</summary>
I'm playing around with `libfprint` and I created a really simple function:
```c
#include <libfprint-2/fprint.h>
#include <glib-2.0/glib-unix.h>
void start_device() {
FpContext *ctx = fp_context_new();
fp_context_enumerate(ctx);
}
int main() {
start_device();
}
I'm compiling with gcc using gcc -fsanitize=address
and I'm getting memory leaks and I can't figure out why.
Edit: Output
=================================================================
==55025==ERROR: LeakSanitizer: detected memory leaks
Direct leak of 3 byte(s) in 1 object(s) allocated from:
#0 0x7f14a8aba6af in __interceptor_malloc (/lib64/libasan.so.8+0xba6af)
#1 0x7f14a56d3017 in __vasprintf_internal (/lib64/libc.so.6+0x80017)
#2 0x7af10c9e9cbbccff (<unknown module>)
SUMMARY: AddressSanitizer: 3 byte(s) leaked in 1 allocation(s).
Edit 2: If I delete fp_context_enumerate(ctx);
I don't get memory leaks, so I guess there's the problem but I don't know why.
答案1
得分: 2
1 这个函数被标记为transfer full
,意味着它将完全的责任转移到调用者身上,关于指针的情况可以参考这里以获取更多细节。
这意味着在完成后,你需要负责释放它。并且,通过释放,我不指的是正常的C free
函数。返回的指针是一个GObject
类型,因此你应该简单地使用g_object_unref
释放它,让对象引用计数框架来处理实际的释放。
换句话说,类似于:
#include <libfprint-2/fprint.h>
#include <glib-2.0/glib-unix.h>
FpContext *start_device() {
FpContext *ctx = fp_context_new();
fp_context_enumerate(ctx);
return ctx;
}
void stop_device(FpContext *ctx) {
g_object_unref(ctx);
}
int main() {
FpContext *ctx = start_device();
// 做你的操作。
stop_device(ctx);
}
但要记住,未释放的内存和内存泄漏并不一定是相同的事情(甚至不一定是坏事),只有当它们随着时间的推移累积时才会引发问题。
例如,启动代码可能会泄漏从未清理的内存,例如,如果首次调用时创建一个4K缓冲区以进行printf
,那么它可能会依赖于进程退出来“释放”该内存。
显然,这种分配不会是真正的问题,因为它不会持续分配4K,只会在开始时分配一次。从这个意义上说,它不比为你的进程分配一个堆栈更严重
事实上,根据你的编辑:
如果我删除
fp_context_enumerate(ctx);
,我就不会出现内存泄漏,所以我猜问题就在这里,但我不知道为什么。
这正是我上面所说的(由源代码确认)。使用 fp_context_enumerate()
枚举时,第一次为上下文分配一些内存以检测和存储每个指纹扫描设备的详细信息,并且该内存随后保留。
然后,调用 fp_context_get_devices()
将首先调用 fp_enumerate()
(如果已经对该上下文进行了处理,则立即返回),然后返回对在枚举过程中设置的内部数据的指针(1)。
(1) 这就是为什么它是transfer none
操作,它只是为你提供了一个指向内部数据的指针。因为该数据在进程内从未实际释放,所以不需要引用计数。
英文:
That function is tagged with the transfer full
label, meaning it's transferring full responsibility to the caller for the pointer. See here for more detail.
That means you're responsible for freeing it when you're done. And, by freeing, I don't mean the normal C free
function. The returned pointer is a GObject
one, so you should simply g_object_unref
it and let the object reference counting framework take care of the actual freeing.
In other words, something like:
include <libfprint-2/fprint.h>
#include <glib-2.0/glib-unix.h>
FpContext *start_device() {
FpContext *ctx = fp_context_new();
fp_context_enumerate(ctx);
return ctx;
}
void stop_device(FpContext *ctx) {
g_object_unref(ctx);
}
int main() {
FpContext *ctx = start_device();
// Work your magic.
stop_device(ctx);
}
But keep in mind that un-freed memory and memory leaks aren't quite necessarily the same thing (or even a bad thing), it's just when they add up over time that they cause issues.
For example, startup code may leak memory that it never cleans up, such as if a 4K buffer is created once for printf
purposes the first time it's called. It may well rely on process exit to "free" that memory.
Obviously, this allocation won't be a real problem because it's not allocating 4K continuously, just once at the start. In that sense, it's no more serious than having a stack allocated for your process
In fact, based on your edit:
> If I delete fp_context_enumerate(ctx);
, I don't get memory leaks so I guess there's the problem but I don't know why.
That's exactly what I was stating above (confirmed by the source code). Enumerating with fp_context_enumerate()
will, the first time it's called for a context, allocate some memory to detect and store details on each fingerprint scanning device, and that memory is subsequently kept around.
Then a call to fp_context_get_devices()
will first call fp_enumerate()
(which returns immediately if already done for that context), then return a pointer to internal data set up during enumeration <sup>(1)</sup>.
<sup>(1)</sup> That's why it's a transfer none
operation, it just gives you a pointer to internal data. Because that data is never actually freed within the process, there's no reference counting needed for it.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论