Investigating memory leak

Pieter Hulshoff pieter at towel42.nl
Sun Feb 20 13:27:05 UTC 2022


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.

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?


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