如何修复libudev内存泄漏?

Posted

技术标签:

【中文标题】如何修复libudev内存泄漏?【英文标题】:How to fix libudev memory leaks? 【发布时间】:2018-07-12 00:41:43 【问题描述】:

我正在为 hidraw 驱动程序下的 USB 设备实现基于 libudev 的监控代码。我已经从网上实现了标准示例,并使用 valgrind 和 gdb 检查了内存泄漏。

/*******************************************
 libudev example.

 This example prints out properties of
 each of the hidraw devices. It then
 creates a monitor which will report when
 hidraw devices are connected or removed
 from the system.

 This code is meant to be a teaching
 resource. It can be used for anyone for
 any reason, including embedding into
 a commercial product.

 The document describing this file, and
 updated versions can be found at:
    http://www.signal11.us/oss/udev/

 Alan Ott
 Signal 11 Software
 2010-05-22 - Initial Revision
 2010-05-27 - Monitoring initializaion
              moved to before enumeration.
*******************************************/

我很不高兴地发现一些不应该分配内存的 libudev 函数正在泄漏。我通过在不同的点退出(在所有对象都未引用之后)并查看 valgrind 报告来跟踪这一点。具体这段代码泄露:

int main (void)

struct udev *udev;
struct udev_enumerate *enumerate;
struct udev_list_entry *devices, *dev_list_entry;
struct udev_device *dev, *devParent;
struct udev_monitor *mon;
int fd;

/* Create the udev object */
udev = udev_new();
if (!udev) 

    printf("Can't create udev\n");
    exit(1);

/* This section sets up a monitor which will report events when
    blah blah....
   "hidraw" devices. */

/* Set up a monitor to monitor hidraw devices */
mon = udev_monitor_new_from_netlink(udev, "udev");
udev_monitor_filter_add_match_subsystem_devtype(mon, "hidraw", NULL);
udev_monitor_enable_receiving(mon);
/* Get the file descriptor (fd) for the monitor.
   This fd will get passed to select() */
fd = udev_monitor_get_fd(mon);

/* Create a list of the devices in the 'hidraw' subsystem. */
enumerate = udev_enumerate_new(udev);
udev_enumerate_add_match_subsystem(enumerate, "hidraw");
if (1)

    // leak debug block
    udev_enumerate_unref(enumerate);
    udev_monitor_unref(mon);
    udev_unref(udev);
    return 0;

udev_enumerate_scan_devices(enumerate);
devices = udev_enumerate_get_list_entry(enumerate);
/* For each item enumerated, print out its information.

这是 valgrind 的输出:

==11424== HEAP SUMMARY:
==11424==     in use at exit: 4,096 bytes in 1 blocks
==11424==   total heap usage: 11 allocs, 10 frees, 28,086 bytes allocated
==11424== 
==11424== LEAK SUMMARY:
==11424==    definitely lost: 0 bytes in 0 blocks
==11424==    indirectly lost: 0 bytes in 0 blocks
==11424==      possibly lost: 0 bytes in 0 blocks
==11424==    still reachable: 4,096 bytes in 1 blocks
==11424==         suppressed: 0 bytes in 0 blocks
==11424== Rerun with --leak-check=full to see details of leaked memory

如果我将“泄漏调试块”放置在其上述位置之前的一行,则 valgrind 退出时会出现 0 字节泄漏的干净结果。 如果我将代码块向前推进一行,则下一个函数会增加泄漏大小和组件:

==14262==     in use at exit: 8,192 bytes in 2 blocks
==14262==   total heap usage: 45 allocs, 43 frees, 150,907 bytes allocated
==14262== 
==14262== LEAK SUMMARY:
==14262==    definitely lost: 0 bytes in 0 blocks
==14262==    indirectly lost: 0 bytes in 0 blocks
==14262==      possibly lost: 0 bytes in 0 blocks
==14262==    still reachable: 8,192 bytes in 2 blocks
==14262==         suppressed: 0 bytes in 0 blocks
==14262== Rerun with --leak-check=full to see details of leaked memory

在下一行之后情况变得更糟,并且令人担忧,因为我的代码需要运行多年,并且此类泄漏可能会累积而未经检查。

有什么建议为什么会发生以及如何控制它?

【问题讨论】:

欢迎来到 SO。我希望进行一些小的编辑(您的文本中有一个开放的括号和一个开放的引号,没有关闭),但是字符太少了,我无法进行更改。此外,您是否确定哪条线路导致泄漏?我不知道你是否找到了。 您确实应该列出据称泄漏的函数。您描述了您的代码,即“前一行”、“将块向前推进一行”等,但这并没有预先说明哪个函数正在泄漏。您发布的代码是“正确”代码吗?是不是已经“往下推进了一行”?请通过发布非工作代码来澄清,或指定您发布的代码是非工作版本。 @Jeff 引号和括号已更正。 @PaulMcKenzie 泄漏的第一行是code udev_enumerate_add_match_subsystem(enumerate, "hidraw"); valgrind 转储是:==20471== 堆摘要:==20471== 退出时使用:1 个块中的 4,096 字节 ==20471== 总堆使用量:11 次分配,10 次释放,28,086 字节分配 ==20471= = 1 个块中的 4,096 字节仍然可以在 1 的丢失记录 1 中访问(在 /lib/i386-linux-gnu/libudev.so.1.6.5 中)==20471== 由 0x108BAA:主要(在 /home/pi/ projects/eclipse/testUSB/udevHidraw) ==20471== 泄漏摘要:==20471== 仍然可以访问:1 个块中的 4,096 个字节 【参考方案1】:

似乎这些与 valgrind 报告的哈希表相关的内存泄漏不是问题,请参阅讨论 https://github.com/libratbag/libratbag/issues/405 和 https://bugzilla.redhat.com/show_bug.cgi?id=1280334 的相关 Red Hat 错误报告。

【讨论】:

以上是关于如何修复libudev内存泄漏?的主要内容,如果未能解决你的问题,请参考以下文章

如何修复 _NSCFNumber 的 iOS 内存泄漏?

如何修复 AFNetworking 3.1 中的内存泄漏?

如何修复内存泄漏?

如何修复 Valgrind 日志中的内存泄漏

如何修复 AttachedBehavior 上的 DependencyPropertyDescriptor AddValueChanged 内存泄漏?

如何修复 PHP 中的内存泄漏