Я использую оболочку 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;
}
}
I Перебираем этот код с помощью этого цикла:
final VideoCapture vc = new VideoCapture("/path/to/file");
final SimpleIt it = new SimpleIt(vc);
while (it.hasNext) {
it.next();
}
Простое повторение приведет к увеличению потребления памяти линейным. Я вижу, что проблема заключается в первой строке в следующем() - методе. Он всегда создает новый Mat. Но, говоря только о java, этот Mat выйдет из области действия, как только итерационный код перейдет к следующему изображению.
Я мог бы преодолеть эту проблему, не используя новый Mat каждый раз, но переписывая всегда один и тот же Mat-Object, например:
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.
У кого-нибудь есть идея, как это сделать?
Edit:
Поскольку кажется, что не ясно, что проблема с моим вторым решением, я записываю его более явно. Подумайте о следующем коде, используя итератор:
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 будут разные изображения. Но это явно не то, что предполагалось.