Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Memory leak #878

Closed
atshields opened this issue May 4, 2020 · 23 comments
Closed

Memory leak #878

atshields opened this issue May 4, 2020 · 23 comments
Labels

Comments

@atshields
Copy link

I'm struggling with a memory leak whilst calling certain ffmpeg functions.

The following code is an example, the problematic function call (av_guess_frame_rate) is commented out, without this line I can call this code many thousands of times without any signs of leak. With this line there is a steady increase in memory consumption and calls to Pointer.totalBytes() see an increase in 8 bytes per call.

I'm guessing that for some reason the AVRational is not being cleaned up. Running under the debugger the dealocator does appear to be called at the end of the try block.

Is there something else that I need to be doing here? I've tried all sorts of combinations of fr.releaseReference(), fr.deallocate(), fr.close() and Pointer.deallocateReferences().

I've also tried modifying the example program ReadFewFrame to run in a loop. That program takes only a few minutes to grab the maximum allowed memory before crashing.

My maven dependency is :

<dependency>
    <groupId>org.bytedeco</groupId>
    <artifactId>ffmpeg-platform</artifactId>
    <version>4.2.2-1.5.3</version>
</dependency>

I'm running under Amazon Corretto 11.0.6_10 on Windows 10.

    public void test(String filename) {

        try (PointerScope scope=new PointerScope()) {
            AVFormatContext ifmtCtx =  new AVFormatContext(null);
            int rv;

            rv = avformat_open_input(ifmtCtx, filename, null, null);
            if(rv < 0) throw new RuntimeException("Could not open input file " + filename+" error="+rv);

            // load stream information
            rv = avformat_find_stream_info(ifmtCtx, (PointerPointer) null);

            AVStream videoStream = null;
            // find the first video stream
            for(int i = 0; i < ifmtCtx.nb_streams(); i++) {
                AVStream stream = ifmtCtx.streams(i);
                int codecType = stream.codecpar().codec_type();
                if(codecType == AVMEDIA_TYPE_VIDEO) videoStream = stream;
            }

            int codecID = videoStream.codecpar().codec_id();
            AVCodec dec = avcodec_find_decoder(codecID);
            if(dec == null)
                throw new RuntimeException("Could not find decoder for stream " + videoStream.index() + " id " + codecID);

            AVCodecContext codecContext = avcodec_alloc_context3(dec);
            if(codecContext == null)
                throw new RuntimeException("Failed to allocate decoder context for stream " + videoStream.index());
            rv = avcodec_parameters_to_context(codecContext, videoStream.codecpar());
            if(rv < 0) throw new RuntimeException("Failed to copy decoder parameters to input decoder error="+ rv);

            // MEMORY LEAK on this line
            //AVRational fr=av_guess_frame_rate(ifmtCtx, videoStream, null);

            avcodec_close(codecContext);
            avcodec_free_context(codecContext);
            codecContext.close();
            codecContext.releaseReference();
            codecContext.deallocate();

            avformat_close_input(ifmtCtx);
            avformat_free_context(ifmtCtx);

        }
    }

@saudet
Copy link
Member

saudet commented May 4, 2020 via email

@atshields
Copy link
Author

The entire test method is wrapped in a try block with a PointerScope.
I've tried moving it to just surround the problematic method but that doesn't appear to make any difference.
Am I missing something?
Thanks

@saudet
Copy link
Member

saudet commented May 4, 2020

Ah, sorry, I missed that. Well, the only thing that could leak in that case is FFmpeg, so you'll probably find more help about that upstream: https://ffmpeg.org/contact.html

@atshields
Copy link
Author

ok, thanks

@saudet
Copy link
Member

saudet commented May 4, 2020

Also be sure to try on Linux as well. If it doesn't happen there, then it's a bug in GCC on Windows.

@saudet
Copy link
Member

saudet commented May 5, 2020

Yup, I'm unable to reproduce this on Linux, no crash or signs of a memory leak after over 2 hours, so it must be a bug in GCC on Windows. We need GCC to build FFmpeg itself, but we should still be able to compile the JNI wrappers with MSVC and that might help. Could you give it a try? It should only be a matter of removing these lines from the pom.xml file: https://github.com/bytedeco/javacpp-presets/blob/master/ffmpeg/pom.xml#L55-L83

The reason Pointer.totalBytes() doesn't decrease is just because it gets updated by the GC. If you need the correct value, make sure to call System.gc() before querying it. We can also set the "org.bytedeco.javacpp.nopointergc" system property to "true" to get more deterministic behavior, but I've noticed a memory leak in the implementation of Pointer.deallocate() in that case. I've just pushed a fix for that though, so be sure to grab the latest version! Thanks

@atshields
Copy link
Author

Ok thanks, sorry only just saw this - in the end I implemented that particular method in java.

This may take me some time as I haven't worked with c for nearly 20 years. I'm just installing the tools...

@saudet
Copy link
Member

saudet commented May 7, 2020

No worries, but I'm not able to reproduce this issue with Oracle JDK 8 on Windows 10 either, so it's probably not related to GCC. There must be something special about your particular machine...

@nanguantong
Copy link
Contributor

I have the same problem while called the same steps. @saudet

@saudet
Copy link
Member

saudet commented Sep 21, 2020

Like I said, it works fine for me. I am unable to reproduce this issue. Unless you can provide any additional information, I will not be able to do anything about this.

@nanguantong
Copy link
Contributor

nanguantong commented Sep 21, 2020

image

Running multiple times or several days and then show oom.

@saudet
Copy link
Member

saudet commented Sep 21, 2020

That's probably caused by something else in your application. If that doesn't concern you though, simply disable that check.

@nanguantong
Copy link
Contributor

@saudet
Hi,
Now I do not add PointerScope , OOM always occured, I want to know if or not need to add PointerScope at the beginning of the function? as following:

 try (PointerScope scope=new PointerScope()) {
 }

@saudet
Copy link
Member

saudet commented Sep 28, 2020 via email

@nanguantong
Copy link
Contributor

nanguantong commented Sep 28, 2020

I use ffmpeg preset with ffmpegPlatformVersion = '4.3.1-1.5.4', if or not needed?

@saudet
Copy link
Member

saudet commented Sep 28, 2020

If you're using the API of FFmpeg directly, then, yes, any allocated Pointer should be used within a PointerScope.

@nanguantong
Copy link
Contributor

Ok.
if or not need to use retainReference or releaseReference() for each Pointer object ?

@saudet
Copy link
Member

saudet commented Sep 28, 2020

You can use those methods as well, but it's easier to use PointerScope, which will call them as needed.

@nanguantong
Copy link
Contributor

nanguantong commented Sep 28, 2020

I see some of Pointer objects used xxReference() (e.g. video_pkt = new AVPacket().retainReference()) and some of Pointer objects not used xxReference() (avio = avio_alloc_context(new BytePointer(av_malloc(4096));) in FFmpegFrameRecorder.java, so some tricks or rules for this?

@saudet
Copy link
Member

saudet commented Sep 28, 2020

Not really, it was just easier for me to do it without a PointerScope in those cases because I know how it works, but you don't need to do it that way. :)

@saudet
Copy link
Member

saudet commented Sep 28, 2020

@nanguantong
Copy link
Contributor

Yeh, I have seen it, so the PointerScope act as clearing the objects memory within the try(...) code block while it runs over immediately.

@saudet
Copy link
Member

saudet commented Jan 19, 2022

I'm assuming that it's working fine now without memory leaks with all the fixes and everything, but please let me know if you're still having issues this! Thanks

@saudet saudet closed this as completed Jan 19, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

3 participants