我使用的是OpenCV的Java包装。我试图在电影的框架上编写一个迭代器。我的问题是迭代器是一个巨大的内存泄漏。这里是迭代器,它具有这种泄漏的一个非常简化的版本:内存从迭代Opencv帧泄漏
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;
}
}
我遍历使用此循环验证码:
final VideoCapture vc = new VideoCapture("/path/to/file");
final SimpleIt it = new SimpleIt(vc);
while (it.hasNext) {
it.next();
}
只是迭代会增加内存消耗的线性。我发现问题是下一个()方法的第一行。它总是创建一个新的垫子。但是单独谈论java,只要迭代代码迭代到下一个图像,该Mat就会超出范围。
我可以克服这个问题,不使用每当新垫,但总是覆盖相同垫对象,像这样:
private final VideoCapture capture;
private final Mat mat = new Mat();
boolean hasNext;
@Override
public Mat next() {
capture.retrieve(mat);
hasNext = capture.grab();
return mat;
}
但现在这是由迭代给出的最后一帧会被覆盖。因此,如果我对这个单一框架感兴趣,我不能将它放在外面供以后使用。当然,我可以复制它,但这也会很昂贵。
我认为问题在于垃圾收集器不会销毁Mat对象,因为它不能识别内存消耗,因为它不是Java堆空间。在循环中调用mat.release()将有所帮助,但当然在实际代码中,这意味着我的Mat对象不会有垃圾回收。
任何人有一个想法如何做到这一点?
编辑:
因为它似乎并没有被清楚我的第二个解决方案是什么问题,我把它写下来更明确。想想下面的代码,使用迭代:
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将是不同的图像。但这显然不是预期的。
你运行内存不足?如果没有,那么这不是泄漏 - GC将在需要时运行。 –
是的,我这样做。在几秒钟内,一些技嘉已满。 – Matthias