GNOME Bugzilla – Bug 683470
Unix socket fd leaks and memory leaks when use pipeline
Last modified: 2012-09-06 12:00:19 UTC
We usually use the code as below. //===================================== GMainLoop *loop; GstBus *bus; GstElement *pipeline,*source,*typefind,*sink; gst_init(NULL, NULL); loop = g_main_loop_new(NULL, FALSE); //create element pipeline = gst_pipeline_new("my_pipeline"); typefind = gst_element_factory_make("typefind","typefind1"); sink = gst_element_factory_make("fakesink","sink1"); source = gst_element_factory_make("souphttpsrc","source1"); if (!pipeline || !source || !typefind || !sink) { return; } g_object_set (G_OBJECT(source), "location", _cUrl, NULL); bus = gst_pipeline_get_bus(GST_PIPELINE(pipeline)); //here will ref bus gst_bus_add_watch(bus, bus_watch, loop); //here will ref bus gst_object_unref(bus); //but only unref bus once gst_bin_add_many(GST_BIN(pipeline), source, typefind, sink, NULL); gst_element_link(source,typefind); gst_element_link(typefind,sink); g_main_loop_run(loop); gst_element_set_state(pipeline,GST_STATE_NULL); gst_object_unref(GST_OBJECT(pipeline)); //===================================== Gstreamer example code is the same usage. Note this: bus = gst_pipeline_get_bus(GST_PIPELINE(pipeline)); //here will ref bus gst_bus_add_watch(bus, bus_watch, loop); //here will ref bus gst_object_unref(bus); //but only unref bus once (gst_pipeline_get_bus --> gst_element_get_bus) will ref bus. (gst_bus_add_watch ---> gst_bus_add_watch_full_unlocked---> gst_bus_create_watch) will ref bus. Then will ref bus twice, and only unref once. So when we call "gst_object_unref(GST_OBJECT(pipeline));" at end of the application, the pipeline bus will not freed. When the pipeline created, it will create bus, and bus will create gstpoll. look at gstpoll codes, GstPoll * gst_poll_new (gboolean controllable) { GstPoll *nset; GST_DEBUG ("controllable : %d", controllable); nset = g_slice_new0 (GstPoll); g_mutex_init (&nset->lock); #ifndef G_OS_WIN32 nset->mode = GST_POLL_MODE_AUTO; nset->fds = g_array_new (FALSE, FALSE, sizeof (struct pollfd)); nset->active_fds = g_array_new (FALSE, FALSE, sizeof (struct pollfd)); nset->control_read_fd.fd = -1; nset->control_write_fd.fd = -1; { gint control_sock[2]; if (socketpair (PF_UNIX, SOCK_STREAM, 0, control_sock) < 0) goto no_socket_pair; //================================= It will use socketpair to create two sockets, but not closed when pipeline destroyed because the bus ref count is 2. You can use lsof to check fd number
That's to say the bus of the pipeline is not destroyed, because the ref count of the bus is not 1
The bus watch probably keeps a ref to the bus as well. Try: id = gst_bus_add_watch (..); ... g_source_remove (id);
If I use gst_element_set_state(pipeline,GST_STATE_NULL); gst_object_unref(GST_OBJECT(pipeline)); g_source_remove(id); It will be ok. Thank you Tim. I think you should add this to the example code.
The problem really is because the mainloop is not unreffed.
Then how we can avoid it. Is it a gstreamer inner bug or a programmer bug ?
programmer bug. Do g_main_loop_unref (loop) after unreffing the pipeline.
> The problem really is because the mainloop is not unreffed. But the watch is hooked up on the default main context (which I believe is never destroyed once created), so you can do multiple g_main_loop_run()/quit()/run(), so I think the fd leak is really due to the source not having been removed.
I use gst_element_set_state(pipeline,GST_STATE_NULL); gst_object_unref(GST_OBJECT(pipeline)); g_main_loop_unref(loop); still have fd leak. Every time leak two fds.
Acossing to my debuging, I think the source is removed.
+ Trace 230809
The leaked fd is created by socketpair. It belongs to the pipeline element, not belongs to src
Ah, indeed. Then you need to explicitly remove the source or make a custom context. It's not so nice.. Does the source really need a ref to the bus? If removing the last ref on the bus would also remove the source, it would perhaps be nicer..
(In reply to comment #9) > Acossing to my debuging, I think the source is removed. > > The leaked fd is created by socketpair. It belongs to the pipeline element, not > belongs to src The socketpair is from the bus object, which is not freed because the source has a ref to it and is not freed.
Hi Wim, Then How to write my code. Do you mean explicitly call gst_object_unref(GST_OBJECT(src)); or call gst_object_unref(bus) twice. Calling gst_object_unref(bus) twice will cause segment failed.
(In reply to comment #11) > (In reply to comment #9) > > Acossing to my debuging, I think the source is removed. > > > > The leaked fd is created by socketpair. It belongs to the pipeline element, not > > belongs to src > > The socketpair is from the bus object, which is not freed because the source > has a ref to it and is not freed. The only way to close the socket is when bus is destroyed. When the bus destroyed, it call gst_poll_free. In gst_poll_free, it will close the socket. static void gst_bus_dispose (GObject * object) { GstBus *bus = GST_BUS (object); if (bus->priv->queue) { GstMessage *message; g_mutex_lock (&bus->priv->queue_lock); do { message = gst_atomic_queue_pop (bus->priv->queue); if (message) gst_message_unref (message); } while (message != NULL); gst_atomic_queue_unref (bus->priv->queue); bus->priv->queue = NULL; g_mutex_unlock (&bus->priv->queue_lock); g_mutex_clear (&bus->priv->queue_lock); if (bus->priv->poll) gst_poll_free (bus->priv->poll); bus->priv->poll = NULL; } G_OBJECT_CLASS (parent_class)->dispose (object); }
I think the cause is that the bus is not freed. How to free the bus?
(In reply to comment #14) > I think the cause is that the bus is not freed. How to free the bus? What Tim said: id = gst_bus_add_watch (..); ... g_source_remove (id);
(In reply to comment #15) > (In reply to comment #14) > > I think the cause is that the bus is not freed. How to free the bus? > > What Tim said: > > id = gst_bus_add_watch (..); > ... > g_source_remove (id); Yes , this way is ok as I had replied in comment 3.
Hello All, Thank you for your replay with patience. I think gst example codes should also add this code. I will mark it NOTABUG.
We'll fix the example, thanks.