gstreamer-java / gst1-java-core

Java bindings for GStreamer 1.x
GNU Lesser General Public License v3.0
188 stars 72 forks source link

What is proper way to dispose the whole pipeline? #170

Closed simophin closed 4 years ago

simophin commented 5 years ago

Hi,

We have a Java application that creates/destroys pipelines dynamically. After a while the app runs out of file descriptors. We found that this is due to the pipelines we created never get freed in native land (observed through GST_DEBUG=4).

We already make sure the pipeline.disposed() is called when it's no longer needed.

There are two things we discovered while investigating this issue:

  1. Our application's memory usage is minimal and it never gets GC'ed for weeks.
  2. Once we add System.gc() after disposing pipeline, pipelines are all disposed and freed.

However, I don't think calling System.gc() is anywhere near an ideal solution, given our app is already highly optimized to avoid GC as much as possible, introducing it back is only going to set us back ages.

So I'm wondering, what is the proper way to dispose the native pipeline on demand?

neilcsmith-net commented 5 years ago

Can you confirm whether you're using GStreamer 1.14 or 1.16? I've had other reports of something similar affecting only 1.16. At the moment, not sure of the cause for that. If you're doing explicit close, worth checking the reference count just before you call it. Also, track in VisualVM or similar whether some reference is being held somewhere it shouldn't be.

You may want to jump on the mailing list, where you'll get more eyes on this, or email me privately if you want to discuss specific support.

simophin commented 5 years ago

We are using GStreamer 1.14.

I asked this question because I didn't see any one stop solution to clean up all Java references. We also have Java calls like pipeline.getBus().connect(), or pipeline.getChildElement() etc. They all create Java objects (strong references) to the native land eh? I tried to collect and close as many of them as possible but still no luck.

neilcsmith-net commented 5 years ago

I assume you're stopping the Pipeline before disposing? Relying on GC is always problematic with Java for managing native resources. It works for some simple use cases. All native objects also support try with resources, or you can just call dispose(). This releases the extra ref count added by the Java bindings. You could try wrapping all GObjects, things like elements from getChildElement(), so they're unreffed when you've finished whatever you're doing with them. Just don't do this with Bus - that is managed internally by the Pipeline.