内存从迭代Opencv帧泄漏 [英] Memory Leak from iterating Opencv frames

查看:158
本文介绍了内存从迭代Opencv帧泄漏的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在使用OpenCV的java包装器。我试图在电影的帧上写一个迭代器。我的问题是迭代器是一个巨大的内存泄漏。这是迭代器的一个非常简化的版本,它有这个泄漏:

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 version of the iterator, which has this leak:

public static final class SimpleIt implements Iterator<Mat> {

    private final VideoCapture capture;
    boolean hasNext;

    public SimpleIt(final VideoCapture capture) {
        this.capture = capture;
        hasNext = capture.grab();
    }

    @Override
    public boolean hasNext() {
        return hasNext;
    }

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

我使用此循环迭代此代码:

I Iterate over this code using this loop:

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

只需迭代就会增加线性内存消耗。我看到问题是next() - Method中的第一行。它总是创造一个新的垫子。但是说到单独的java,一旦迭代代码迭代到下一个图像,这个Mat就会超出范围。

Just iterating will increase memory consumption linear. I see that the problem is the first line in the next()-Method. It always creates a new Mat. But speaking of java alone, this Mat will run out of scope as soon as the iterating code iterates to the next image.

我可以通过不使用a来克服这个问题每次新Mat,但覆盖总是相同的Mat-Object,如下所示:

I could overcome the problem, by not using a new Mat every time, but overwriting always the same Mat-Object, like this:

    private final VideoCapture capture;
    private final Mat mat = new Mat();
    boolean hasNext;

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

但现在迭代器给出的最后一帧将被覆盖。因此,如果我对这个单帧感兴趣,我不能把它放在外面供以后使用。当然,我可以复制它,但这也很昂贵。

But now the last frame which was given by the iterator will be overwritten. Thus, I cannot hold it outside for later use, if I am interested in this single frame. I could copy it, of course, but that would also be expensive.

我认为问题是垃圾收集器不会破坏Mat对象,因为它确实不承认内存消耗,因为它不是java堆空间。在循环中调用mat.release()会有所帮助,但当然在实际代码中这意味着我的Mat对象没有垃圾收集。

I assume that the problem is that the garbage collector will not destroy the Mat objects, because it does not recognize the memory consumption, since it is not java heap space. Calling mat.release() in the loop will help, but of course in real code this means I will have no garbage collection for my Mat objects.

任何人都有一个想法怎么做?

Anybody has an idea how to do it?

编辑:

因为似乎不清楚我的第二个问题是什么解决方案是,我更明确地写下来。使用迭代器考虑以下代码:

Since it seems not to be clear what the problem with my second solution is, I write it down more explicitly. Think about the following code, using the iterator:

    final VideoCapture vc = new VideoCapture("/path/to/file");
    final SimpleIt it = new SimpleIt(vc);
    int i = 0;
    Mat save = null;
    while (it.hasNext) {
        final Mat next = it.next();
        if (i == 10) {
            save = next;
            Highgui.imwrite("/path/to/10.png", save);
        } else if (i == 30) {
            Highgui.imwrite("/path/to/30.png", save);
        }
        i++;
    }

使用迭代器的第二个版本,10.png和30.png将是不同的图像。但这显然不是预期的。

With the second version of the iterator, 10.png, and 30.png will be different images. But that's obviously not what was intended.

推荐答案

你应该打电话给 mat.release( )

You should really call mat.release().

我的申请中与你的问题非常类似。帧速率非常高,以至于java堆长大到可用的总系统内存,这有时会导致JVM崩溃。 GC太慢了,我没有任何机制来检查可用内存并等待,如果这还不够。

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.

一个解决方案是减少帧只需使用 Thread.sleep(),这当然似乎是不可接受的。但它帮助GC按时完成工作。

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.

最后使用 mat.release()修复了问题。

Finally using mat.release() fixed the problem.

您不必担心Mat对象的垃圾收集,因为此调用仅释放基础数据。当正确的时间到来时,GC将处理Java对象包装器。

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.

这篇关于内存从迭代Opencv帧泄漏的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆