Hey Adrien, > > I need your help to resolve a memory leak problem. I make some tests with a > little and simple software: > > int main(int argc, char* argv[]) > { > > MMManager *manager; > GError *error = NULL; > GDBusConnection *connection = g_bus_get_sync(G_BUS_TYPE_SYSTEM, NULL, > &error); > > while(1){ > > manager = mm_manager_new_sync(connection, > > G_DBUS_OBJECT_MANAGER_CLIENT_FLAGS_DO_NOT_AUTO_START, > NULL, &error); > g_object_unref(manager); > sleep(1); > } > } > > After each loop the memory usage is increased by 4 kB, the object manager > doest not seem to be free. > > This problem with g_object_unref() appears only with objects with MMManager > type. >
I modified your tester to add an additional unref() for the GDBusConnection, as that wasn't getting disposed, but that still wasn't enough. Here's what valgrind finds on your tester after I added the extra GDBusConnection unref: ==43435== 31,680 bytes in 990 blocks are still reachable in loss record 2,179 of 2,182 ==43435== at 0x483977F: malloc (vg_replace_malloc.c:309) ==43435== by 0x4C02FA8: g_malloc (gmem.c:102) ==43435== by 0x4BFAE3F: g_source_set_callback (gmain.c:1758) ==43435== by 0x4A7A311: call_destroy_notify.part.0 (gdbusconnection.c:266) ==43435== by 0x4A7A5E2: call_destroy_notify (gdbusconnection.c:257) ==43435== by 0x4A7A5E2: signal_subscriber_unref (gdbusconnection.c:3286) ==43435== by 0x4A7A5E2: signal_subscriber_unref (gdbusconnection.c:3278) ==43435== by 0x4BCC705: ptr_array_remove_index (garray.c:1545) ==43435== by 0x4A7DF9E: unsubscribe_id_internal (gdbusconnection.c:3645) ==43435== by 0x4A8225A: g_dbus_connection_signal_unsubscribe (gdbusconnection.c:3717) ==43435== by 0x4A8CDCC: g_dbus_proxy_finalize (gdbusproxy.c:189) ==43435== by 0x4B6727D: g_object_unref (gobject.c:3499) ==43435== by 0x4B6727D: g_object_unref (gobject.c:3391) ==43435== by 0x4BE9D61: g_hash_table_remove_all_nodes.part.0 (ghash.c:706) ==43435== by 0x4BEB10E: g_hash_table_remove_all_nodes (ghash.c:628) ==43435== by 0x4BEB10E: g_hash_table_unref (ghash.c:1461) ==43435== ==43435== 38,610 bytes in 990 blocks are still reachable in loss record 2,180 of 2,182 ==43435== at 0x483977F: malloc (vg_replace_malloc.c:309) ==43435== by 0x4C02FA8: g_malloc (gmem.c:102) ==43435== by 0x4C1CD5F: g_strdup (gstrfuncs.c:363) ==43435== by 0x4BFB490: g_source_set_name (gmain.c:2082) ==43435== by 0x4A7A320: call_destroy_notify.part.0 (gdbusconnection.c:270) ==43435== by 0x4A7A5E2: call_destroy_notify (gdbusconnection.c:257) ==43435== by 0x4A7A5E2: signal_subscriber_unref (gdbusconnection.c:3286) ==43435== by 0x4A7A5E2: signal_subscriber_unref (gdbusconnection.c:3278) ==43435== by 0x4BCC705: ptr_array_remove_index (garray.c:1545) ==43435== by 0x4A7DF9E: unsubscribe_id_internal (gdbusconnection.c:3645) ==43435== by 0x4A8225A: g_dbus_connection_signal_unsubscribe (gdbusconnection.c:3717) ==43435== by 0x4A8CDCC: g_dbus_proxy_finalize (gdbusproxy.c:189) ==43435== by 0x4B6727D: g_object_unref (gobject.c:3499) ==43435== by 0x4B6727D: g_object_unref (gobject.c:3391) ==43435== by 0x4BE9D61: g_hash_table_remove_all_nodes.part.0 (ghash.c:706) ==43435== ==43435== 43,560 bytes in 1,089 blocks are still reachable in loss record 2,181 of 2,182 ==43435== at 0x483977F: malloc (vg_replace_malloc.c:309) ==43435== by 0x4C02FA8: g_malloc (gmem.c:102) ==43435== by 0x4C1AF21: g_slice_alloc (gslice.c:1025) ==43435== by 0x4C1B549: g_slice_alloc0 (gslice.c:1051) ==43435== by 0x4BFA73B: g_source_new (gmain.c:945) ==43435== by 0x4BFE322: g_idle_source_new (gmain.c:5780) ==43435== by 0x4A7A2EB: call_destroy_notify.part.0 (gdbusconnection.c:264) ==43435== by 0x4A7A5E2: call_destroy_notify (gdbusconnection.c:257) ==43435== by 0x4A7A5E2: signal_subscriber_unref (gdbusconnection.c:3286) ==43435== by 0x4A7A5E2: signal_subscriber_unref (gdbusconnection.c:3278) ==43435== by 0x4BCC705: ptr_array_remove_index (garray.c:1545) ==43435== by 0x4A7DF9E: unsubscribe_id_internal (gdbusconnection.c:3645) ==43435== by 0x4A8225A: g_dbus_connection_signal_unsubscribe (gdbusconnection.c:3717) ==43435== by 0x4A8CDCC: g_dbus_proxy_finalize (gdbusproxy.c:189) ==43435== ==43435== 95,040 bytes in 990 blocks are still reachable in loss record 2,182 of 2,182 ==43435== at 0x483BB65: calloc (vg_replace_malloc.c:762) ==43435== by 0x4C03000: g_malloc0 (gmem.c:132) ==43435== by 0x4BFA72E: g_source_new (gmain.c:944) ==43435== by 0x4BFE322: g_idle_source_new (gmain.c:5780) ==43435== by 0x4A7A2EB: call_destroy_notify.part.0 (gdbusconnection.c:264) ==43435== by 0x4A7A5E2: call_destroy_notify (gdbusconnection.c:257) ==43435== by 0x4A7A5E2: signal_subscriber_unref (gdbusconnection.c:3286) ==43435== by 0x4A7A5E2: signal_subscriber_unref (gdbusconnection.c:3278) ==43435== by 0x4BCC705: ptr_array_remove_index (garray.c:1545) ==43435== by 0x4A7DF9E: unsubscribe_id_internal (gdbusconnection.c:3645) ==43435== by 0x4A8225A: g_dbus_connection_signal_unsubscribe (gdbusconnection.c:3717) ==43435== by 0x4A8CDCC: g_dbus_proxy_finalize (gdbusproxy.c:189) ==43435== by 0x4B6727D: g_object_unref (gobject.c:3499) ==43435== by 0x4B6727D: g_object_unref (gobject.c:3391) ==43435== by 0x4BE9D61: g_hash_table_remove_all_nodes.part.0 (ghash.c:706) ==43435== ==43435== LEAK SUMMARY: ==43435== definitely lost: 0 bytes in 0 blocks ==43435== indirectly lost: 0 bytes in 0 blocks ==43435== possibly lost: 2,664 bytes in 27 blocks ==43435== still reachable: 515,070 bytes in 9,835 blocks ==43435== of which reachable via heuristic: ==43435== length64 : 4,944 bytes in 57 blocks ==43435== newarray : 1,936 bytes in 41 blocks ==43435== suppressed: 0 bytes in 0 blocks There are no "memory leaks" per se; instead, there is memory that is allocated but it is still reachable at program exit. The blocks reported above are due to idle sources scheduled in the default GMainContext, looks like there is some "cleanup in idle" logic happening in the GDBusConnection object. That allocated memory is triggered by creating the MMManager, and once the manager is unref-ed, one "cleanup in idle" action is queued in the GDBusConnection, something like that. So if you create 100 MMManagers and unref them right away, all of those will end up scheduling the "cleanup in idle" actions in the GDBusConnection. I assume your program doesn't have a GMainLoop? I'm not totally sure why those cleanups are scheduled in idle (instead of just running the cleanup without scheduling anything), I'd need to dig in the GLib code. I did a quick hack just setting up a quick main loop with 1s timeout before exit (see attached), and all that memory gets correctly freed before exit. Not saying you should do that, that was just a test to validate assumptions. Just using the "sync" APIs in libmm-glib and creating multiple MMManager objects just to dispose them should be a supported thing, but why is your program creating multiple MMManager objects anyway? Maybe we can find another way to solve this issue if you're not planning in setting up a GLib main loop in your code. -- Aleksander https://aleksander.es
#include <libmm-glib.h> static gboolean stop_loop (GMainLoop *loop) { g_main_loop_quit (loop); } int main(int argc, char* argv[]) { MMManager *manager; GError *error = NULL; GDBusConnection *connection = g_bus_get_sync(G_BUS_TYPE_SYSTEM, NULL, &error); gint i = 0; while(++i < 100){ manager = mm_manager_new_sync(connection, G_DBUS_OBJECT_MANAGER_CLIENT_FLAGS_DO_NOT_AUTO_START, NULL, &error); g_object_unref(manager); g_usleep(100000); } g_object_unref (connection); if (0) { GMainLoop *loop; loop = g_main_loop_new (NULL, FALSE); g_timeout_add_seconds (1, (GSourceFunc)stop_loop, loop); g_main_loop_run (loop); g_main_loop_unref (loop); } }
_______________________________________________ ModemManager-devel mailing list ModemManager-devel@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/modemmanager-devel