Investigating memory leak

Nicolas Dufresne nicolas at ndufresne.ca
Sun Feb 20 20:49:22 UTC 2022


Hi,

Le dimanche 20 février 2022 à 14:27 +0100, Pieter Hulshoff via gstreamer-devel a
écrit :
> Greetings all,
> 
> 
> I'm the programmer of the RetroFE arcade and emulation front-end. The 
> RetroFE code uses gstreamer for its video playback (and SDL for the 
> display). One of its features is a scrolling video wall, where the user 
> can scroll through playing videos of the different games in order to 
> select the game they want to play. It was brought to my attention that 
> this feature leaks memory, and so I've been trying to locate the source 
> of the problem. Unfortunately, I'm not the author of the video code (the 
> original author retired more than 5 years ago), and I'm struggling a bit 
> in understanding what may be the culprit here.
> 
> 
> I've managed to strip the code down to the minimum in order to 
> investigate this under Linux using gstreamer 1.18.0. What I found was 
> that the problem appears to be focused on the waiting time between 
> opening and closing the video (which can be quite short when scrolling 
> fast through the list). My test code opens, plays, and closes a video 
> file 10,000 times. Depending on the waiting time before closing the 
> video, I notice the following:
> 
> 100 ms: memory remains stable at about 1%
> 
> 80 ms: memory remains stable at about 1.1%.
> 
> 40 ms: memory steadily increases to about 5.6%.
> 
> 20 ms: memory steadily increase to about 7.9%.
> 
> 10 ms: memory rapidly increases to about 28% after only 2,000 cycles, 
> after which it throws "Failed to load cookie file from cookie: Too many 
> open files" error messages.

There was a very similar report recently:

https://gitlab.freedesktop.org/gstreamer/gstreamer/-/issues/968#note_1252868

In that report, this type of leak happened in if the bus was unreffed after its
owner (playbin or the pipeline). Though, I'm run your code here on 1.20.0, and
there was no leak after 3000 iterations.

> 
> Any and all thoughts and solutions would be welcome.
> 
> 
> In addition, uncommenting the
> 
> //        gst_object_unref( videoSink );
> 
> //        gst_object_unref( videoConvert );
> 
> //        gst_object_unref( videoBin );
> 
> lines gives runtime assertions on refCount > 0. I assume this is because 
> "gst_object_unref( playbin );" already unreferences these elements?

This is normal, gst_element_factory_make() returns a floating reference, and
gst_bin_add() will acquire the floating reference, which means your code no
longer owns the object.

> 
> 
> Kind regards,
> 
> 
> Pieter Hulshoff
> 
> -----
> 
> #include <gst/gst.h>
> #include <string>
> #include <unistd.h>
> #include <iostream>
> 
> 
> int main( int argc, char *argv[] )
> {
> 
>      GstElement *playbin, *videoBin, *videoSink, *videoConvert;
>      GstCaps    *videoConvertCaps;
>      GstBus     *videoBus;
>      GstBuffer  *videoBuffer;
>      GstPad     *videoConvertSinkPad, *videoSinkPad;
>      std::string file;
> 
>      gst_init( NULL, NULL );
> 
>      file = gst_filename_to_uri( "test.avi", NULL );
> 
>      for( int i = 1; i <= 10000; i++ )
>      {
> 
>          playbin          = gst_element_factory_make( "playbin", "player" );
>          videoBin         = gst_bin_new("SinkBin");
>          videoSink        = gst_element_factory_make("fakesink", 
> "video_sink");
>          videoConvert     = gst_element_factory_make("capsfilter", 
> "video_convert");
>          videoConvertCaps = 
> gst_caps_from_string("video/x-raw,format=(string)I420,pixel-aspect-ratio=(fraction)1/1");
> 
>          std::cout << "Starting test round " << i << std::endl;
>          gst_bin_add_many( GST_BIN( videoBin ), videoConvert, videoSink, 
> NULL );
>          gst_element_link_filtered( videoConvert, videoSink, 
> videoConvertCaps );
>          videoConvertSinkPad = gst_element_get_static_pad( videoConvert, 
> "sink" );
>          g_object_set( G_OBJECT( videoSink ), "sync", TRUE, "qos", 
> FALSE, NULL );
>          videoSinkPad = gst_ghost_pad_new( "sink", videoConvertSinkPad );
>          gst_element_add_pad( videoBin, videoSinkPad );
>          gst_object_unref( videoConvertSinkPad );
>          videoConvertSinkPad = NULL;
>          g_object_set( G_OBJECT( playbin ), "uri", file.c_str(), 
> "video-sink", videoBin, NULL );
>          g_object_set( G_OBJECT( videoSink ), "signal-handoffs", TRUE, 
> NULL );
>          videoBus = gst_pipeline_get_bus( GST_PIPELINE( playbin ) );
>          gst_element_set_state( GST_ELEMENT( playbin ), GST_STATE_PLAYING );
> 
>          usleep( 100000 );
> 
>          g_object_set( G_OBJECT( videoSink ), "signal-handoffs", FALSE, 
> NULL );
>          gst_element_set_state( playbin, GST_STATE_NULL );
>          gst_object_unref( videoBus );
>          videoBus = NULL;
>          gst_object_unref( playbin );
>          playbin = NULL;
> //        gst_object_unref( videoSink );
>          videoSink = NULL;
> //        gst_object_unref( videoConvert );
>          videoConvert = NULL;
>          gst_caps_unref( videoConvertCaps );
>          videoConvertCaps = NULL;
> //        gst_object_unref( videoBin );
>          videoBin = NULL;
> 
>      }
> 
>      return 0;
> }
> -----
> 
> 



More information about the gstreamer-devel mailing list