gstreamer-java/gst1-java-core

native memory still exists after Pipeline.close

JamesTangChengDu opened this issue · 6 comments

native memory still exists after Pipeline.close

Please provide contextual information and a code example that demonstrates this problem, or this issue will be closed. This is not a general problem, so is being triggered by something specific to your usage or code. Thanks.

Thanks for your reply, I will upload a demo code later.

1, I execute the following command to run my demo, The heap capacity of the jvm is 3M.
java -Xmx3M -verbose:gc -jar /mnt/tangjun/demo/vdm-0.0.1.jar

2, The source code of my program is as follows: (where the keepAlive function is just to prevent the program from exiting)
/**

  • the main entry of GStreamer Demo.
    */
    public class App {
    private static final int GST_VERSION_MAJOR = 1;
    private static final int GST_VERSION_MINOR = 10;

    /**

    • CM App instance.
      */
      public App() {
      Gst.init(new Version(GST_VERSION_MAJOR, GST_VERSION_MINOR));
      //testGst();

      keepAlive();
      Gst.deinit();
      }

    private void testGst() {
    final Pipeline mPipeline = new Pipeline();

     String url = "rtsp://admin:ThunderSoft88@192.168.10.43/onvif-media/media.amp?profile=profile_1_h264&sessiontimeout=60&streamtype=unicast";
    
     Element src = ElementFactory.make("rtspsrc", "src");
     src.set("location", url);
     src.set("latency", 0);
     src.set("ntp-time-source", 3);
    
     final Element sink = ElementFactory.make("fakesink", "sink");
    
    
     mPipeline.addMany(src, sink);
    
     src.connect(new Element.PAD_ADDED() {
         @Override
         public void padAdded(Element element, Pad pad) {
             Pad sinkPad = sink.getStaticPad("sink");
             try {
                 pad.link(sinkPad);
    
                 System.out.println("Pad " + pad.getName() + " link to Pad"
                         + sinkPad.getName());
             } catch (PadLinkException ex) {
                 System.out.println("Pad link failed : " + ex.getLinkResult());
             }
         }
     });
    
     final String gstCmd = "rtspsrc location="+url+" latency=0 ntp-time-source=3 ! faksink";
    
     System.out.println("demo gstreamer play: " + gstCmd);
     mPipeline.play();
    
     final int buffer_cacher_waiting_time1 = 1000 * 10; // in milliseconds
     new java.util.Timer().schedule(new java.util.TimerTask() {
         @Override
         public void run() {
             System.out.println("demo gstreamer stop: "+ gstCmd);
             mPipeline.stop();
    
             System.out.println("demo gstreamer close: "+ gstCmd);
             mPipeline.close();
         }
     }, buffer_cacher_waiting_time1);
    

    }

    /**

    • keep main thread alive.
      */
      public void keepAlive() {
      synchronized (this) {
      try {
      this.wait();
      } catch (InterruptedException ex) {
      ex.printStackTrace();
      }
      }
      }

    /**

    • The main function for CM.

    */
    public static void main(String[] args) {
    // keep main thread alive
    App main = new App();
    }
    }

3, Below I have 3 test results:
3.1, when the testGst function is commented out in the code, top RES=32.9m. ("top RES=32.9m" means that after executing top command, the value of RES is 32.9M)
3.2, When the testGst function is executed in the code and mPipeline.play() is run, but it has not run to mPipeline.stop, top RES=44.9m
3.3, When 3.2 continues to run, and after mPipeline.stop and mPipeline.close are executed, top RES=46.9m, and the memory does not decrease but increases.
I'm guessing the memory should go back to around "top RES=32.9m" after step 3, right?

The code typesetting is a bit unfriendly, I rearranged it as follows for your convenience:

public class App {

private static final int GST_VERSION_MAJOR = 1;
private static final int GST_VERSION_MINOR = 10;

public App() {
    Gst.init(new Version(GST_VERSION_MAJOR, GST_VERSION_MINOR));
    testGst();

    keepAlive();
    Gst.deinit();
}

private void testGst() {
    final Pipeline mPipeline = new Pipeline();

    String url = "rtsp://admin:ThunderSoft88@192.168.10.43/onvif-media/media.amp?profile=profile_1_h264&sessiontimeout=60&streamtype=unicast";

    Element src = ElementFactory.make("rtspsrc", "src");
    src.set("location", url);
    src.set("latency", 0);
    src.set("ntp-time-source", 3);

    final Element sink = ElementFactory.make("fakesink", "sink");


    mPipeline.addMany(src, sink);

    src.connect(new Element.PAD_ADDED() {
        @Override
        public void padAdded(Element element, Pad pad) {
            Pad sinkPad = sink.getStaticPad("sink");
            try {
                pad.link(sinkPad);

                System.out.println("Pad " + pad.getName() + " link to Pad"
                        + sinkPad.getName());
            } catch (PadLinkException ex) {
                System.out.println("Pad link failed : " + ex.getLinkResult());
            }
        }
    });

    final String gstCmd = "rtspsrc location="+url+" latency=0 ntp-time-source=3 ! faksink";

    System.out.println("demo gstreamer play: " + gstCmd);
    mPipeline.play();

    final int buffer_cacher_waiting_time1 = 1000 * 10; // in milliseconds
    new java.util.Timer().schedule(new java.util.TimerTask() {
        @Override
        public void run() {
            System.out.println("demo gstreamer stop: "+ gstCmd);
            mPipeline.stop();

            System.out.println("demo gstreamer close: "+ gstCmd);
            mPipeline.close();
        }
    }, buffer_cacher_waiting_time1);
}

public void keepAlive() {
    synchronized (this) {
        try {
            this.wait();
        } catch (InterruptedException ex) {
            ex.printStackTrace();
        }
    }
}

public static void main(String[] args) {
    App main = new App();
}

}

Looking forward to your reply, thank you very much.

There are a number of problems in your code, I'm not sure your assumption that all memory will be released is necessarily correct, and it's possible you're seeing some interaction with #244 caused by calling close() off the GStreamer event thread or directly after stop().

A few pointers -

  • Always store the pipeline in a field.
  • Use Gst.main() and Gst.quit() to keep alive.
  • Try to always interact with GStreamer, particularly after starting a pipeline, using Gst.executor() - that will correctly interleave with bus messages, and supports scheduling already (no need for Timer).
  • Don't call close() immediately after stop(). Use Gst.invokeLater() if you want to do this.
  • You don't need to explicitly dispose of anything, but if you do you need to make sure that other things that might interact with the same element have completed.
  • Never call Gst.deinit()

Try looking at the structure of the various examples in https://github.com/gstreamer-java/gst1-java-examples

Moving this into discussions. I don't believe it's a sign of a native memory leak.