GNOME Bugzilla – Bug 568941
Thread leak in libgstpulse due to problematic refcount scheme
Last modified: 2009-01-24 03:07:57 UTC
I spent the last few hours hunting down the cause of leaked threads from applications using gstreamer for playing sound (simple playbin applications). I suppose I've found the problem. It lies in the way gst_pulseprobe_new() and gst_pulseprobe_free() use g_object_ref() and g_object_unref(). Apparently a "probe" is related to an actual source or sink or mixer and so increments its refcount upon construction and decrements it upon destruction. This seems indeed a sensible thing to do if probes are to exist independently of their related source, sink or mixer. Now the problem is that each source, sink or mixer actually owns a probe related to itself, which means that after construction, a source, sink or mixer has a refcount of 2 (not 1). When the last reference to that object is destroyed, there still is a (cyclic) reference to the probe, so the destructor doesn't get called at all. This would be a minor issue as long as the probe, source, sink and mixer in this case did not spawn their own mainloop thread, which, because of the cyclic reference and lack of proper destructor call, doesn't get terminated at all. Applications that make gstreamer automatically probe for pulseaudio end up with a leaked thread each time they want to, e.g. play a sound. This is clearly something that needs to be addressed. I don't know the inner workings of gstreamer well enough to decide whether simply removing the calls to g_object_{ref,unref} in gst_pulseprobe_{new,free}() is correct. To observe the problem, simply instantiate a playbin: GstElement *play = gst_element_factory_make("playbin", "play"); set it to play some wav file: g_object_set(G_OBJECT(play), "uri", "file:///path/to/file.wav", NULL); and make it play several times: gst_element_set_state(play, GST_STATE_PLAYING); gst_element_set_state(play, GST_STATE_NULL); gst_element_set_state(play, GST_STATE_PLAYING); ... gst_element_set_state(play, GST_STATE_NULL); and finally destroy it: gst_object_unref(GST_OBJECT (play)); If you have libgstpulse.so installed, you should observe an increasing number of threads being spawned and ending up simply waiting for poll() to return. I my case, I'm using ALSA for output, this may be significant.
*** This bug has been marked as a duplicate of 567746 ***