Memory Leak from iterating Opencv frames

前端 未结 5 2085
囚心锁ツ
囚心锁ツ 2020-12-14 20:20

I am using the java wrapper of OpenCV. I tried to write an Iterator over frames of a film. My problem is that the iterator is a huge memory leak. Here is a very simplified v

相关标签:
5条回答
  • 2020-12-14 20:52

    I would modify your .hasNext method to:

    public boolean hasNext() {
        return hasNext;
    }
    

    And then the method you described, copied below, should work fine... You will iterate until nothing is left, at which point you can assign that last image to a new Mat object...

    public Mat next() {
        capture.retrieve(mat);
        hasNext = capture.grab();
        return mat;
    }
    

    and then:

    final VideoCapture vc = new VideoCapture("/path/to/file");
    final SimpleIt it = new SimpleIt(vc);
    final Mat lastFrame = new Mat();
    while (it.hasNext) {
        lastFrame = it.next();
    }
    

    I do realize this creates additional memory usage. There is probably a way around this, but it should work fine...

    0 讨论(0)
  • 2020-12-14 20:54

    You should really call mat.release().

    I have very similar problem to yours in my application. The frame rate was so high that java heap grew up to total available system memory, which sometimes led to JVM crash. GC was simply too slow, and I didn't have any mechanism to check of available memory and wait if that wasn't sufficient.

    One solution was to decrease the frame rate by simply using Thread.sleep() which of course didn't seem to be acceptable. But it helped GC to do it's job on time.

    Finally using mat.release() fixed the problem.

    You don't have to worry about garbage collection of Mat objects, because this call deallocates only underlying data. Java object wrapper will be disposed by GC when the right time comes.

    0 讨论(0)
  • 2020-12-14 21:02

    I just want to add my $0.02 as I bumped into this issue when writing an application that will run for a long.

    Mat.release() is called automatically when the Java Mat-wrapper is garbage collected. However, since the Java wrapper is very small compared to the natively allocated object, it might not be garbage-collected fast enough.

    Therefore, you could either do Mat.release() when you know you are done with an object or call System.gc() at regular intervals to force removal of unused objects.

    0 讨论(0)
  • 2020-12-14 21:09

    System.gc(); doesn't work for me.

    I have add the line:

    System.runFinalization();

    A Codesnippet:

        startGC--;
        if (startGC==0) {
            System.gc();
            System.runFinalization();
            startGC=100;
        }
    
    0 讨论(0)
  • 2020-12-14 21:14

    It seems, there is no good solution. I experimented with it now for quite some hours. The best I came up with was calling the garbage collector on a regular basis like this:

        int count = 0;
    
        @Override
        public Mat next() {
            final Mat result = mat;
            mat = new Mat();
            capture.retrieve(mat);
            hasNext = capture.grab();
            if (++count % 200 == 0) {
                System.gc();
            }
            return result;
    

    Since this works, it indicates that my assumption was correct, java does not recognize the RAM allocated from C, and thus does not call the GC, even though the RAM of the machine is running out.

    This is not a very good solution, because it might not be very stable. If anybody else has a better idea, I am interested.

    0 讨论(0)
提交回复
热议问题