Grande vazamento de memória no opencv
-
21-12-2019 - |
Pergunta
Eu escrevi um programa C++ muito simples para ler 600 quadros de vídeo em um código multithread.o problema é que quando eu libero cada um desses frames o tamanho da memória livre não muda!Estou usando o QT 4.8 e o Ubuntu 12.04, meu tamanho de memória do laptop é de 8 GB, então não tenho nenhuma escassez de memória.
cada quadro tem 1,8 MB, então o tamanho total é 600 * 1,8 MB = 1080 MB
antes de executar o programa, meu tamanho de memória livre é de 6,8 GB, mas depois de executar meu código e deixá-lo terminar, vejo que o tamanho de memória livre é de 5,9 GB, então vejo que há um grande vazamento de memória no programa.Executei meu código 1000 vezes e nunca vi meu programa travar ou enfrentar problemas, então o código está correto.
Meu código:
#include "im_loader.h"
IM_Loader::IM_Loader(QObject *parent) :
QThread(parent)
{
}
void IM_Loader::run()
{
QString PATH = "/home/parsa/QtProjects/MonoSD/";
{
for(float i = 0 ; i < 1 ; i++)
{
QString Folder_Address = PATH + QString::number((int)i)+"/";
QDir Mydir(Folder_Address);
Mydir.setFilter(QDir::Files);
QFileInfoList Vehicles_list = Mydir.entryInfoList();
qDebug()<<"Address is: "<<Folder_Address<<"\n";
qDebug()<<"Number of images are: "<<Vehicles_list.size()<<"\n";
static int overall_counter = 0; //12451
for(int j = 0 ; j < 600 ; j++)
{
if(!Stop_Disp)
{
QString address = Folder_Address + QString::number(overall_counter++) +".jpg";
cv::Mat image = cv::imread(address.toUtf8().constData(),0);
if(!image.data)
{
qDebug()<<"Image Data is failed ... \n";
continue;
}
if(j%100==0)
qDebug()<<"Folder "<<i<<" Image No. "<<j<<" is processed, Overall counter is: "<<overall_counter<<"\n";
cv::Mat Dataaa;
image.copyTo(Dataaa);
QMutexLocker Locker(&Global_Mutex);
PD_Classifier_VEC.push_back(Dataaa);
Locker.unlock();
}
}
}
}
qDebug("Im loader is exited now ...");
}
im_loader.h
#ifndef IM_LOADER_H
#define IM_LOADER_H
#include "Definitions.h"
class IM_Loader : public QThread
{
Q_OBJECT
public:
explicit IM_Loader(QObject *parent = 0);
void run();
bool Stop_Disp;
signals:
public slots:
};
#endif // IM_LOADER_H
Janela principal.cpp
#include "mainwindow.h"
#include "ui_mainwindow.h"
QTimer *Mytimer;
QMutex Global_Mutex;
IM_Loader IML;
std::vector<cv::Mat> PD_Classifier_VEC;
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
IML.start();
Mytimer = new QTimer(this);
Mytimer->singleShot(20000,this,SLOT(Clear_Vec()));
}
void MainWindow::Clear_Vec()
{
qDebug()<<"PD_Classifier_VEC.SIZE IS: "<<PD_Classifier_VEC.size();
for(int i = 0 ; i < PD_Classifier_VEC.size() ; i++)
{
QMutexLocker Locker(&Global_Mutex);
PD_Classifier_VEC.erase(PD_Classifier_VEC.begin() + i);
Locker.unlock();
i--;
}
Mytimer->singleShot(10000,this,SLOT(Clear_Vec()));
}
MainWindow::~MainWindow()
{
delete ui;
}
Janela principal.h
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include "Definitions.h"
namespace Ui {
class MainWindow;
}
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = 0);
~MainWindow();
void Delay(int Milisecond_Delay);
public slots:
void Clear_Vec();
private:
Ui::MainWindow *ui;
};
#endif // MAINWINDOW_H
Definições.h
#ifndef DEFINITIONS_H
#define DEFINITIONS_H
#include <QMainWindow>
#include <QThread>
#include <QTimer>
#include <QDebug>
#include <QDir>
#include <QMutex>
#include <QMutexLocker>
#include <opencv2/imgproc/imgproc.hpp>
#include <opencv2/highgui/highgui.hpp>
#include "im_loader.h"
extern std::vector<cv::Mat> PD_Classifier_VEC;
extern QMutex Global_Mutex;
#endif // DEFINITIONS_H
Eu li em alguns artigos que a versão opencv c++ suporta gerenciamento de memória, então não precisamos nos preocupar com vazamentos de memória.
estou faltando alguma coisa aqui?Eu li essas perguntas também, mas nenhuma delas funcionou para mimesse e esse
Apenas uma postagem me divertiu MUITO e me fez pensar se tenho esse problema no meu código, mas não consegui descobrir. este é o link
Fornecerei qualquer outra coisa, se necessário.
EDITADO:
é muito interessante que se eu adicionar uma função Delay na minha classe imageloader logo após ler cada quadro a quantidade de vazamentos de memória diminui!!!
Meu novo im_loader.cpp
void IM_Loader::Delay(int Milisecond_Delay)
{
double OneSecond = cv::getTickFrequency();
int Milisecond = OneSecond/4000;
for(double t1= 0 ; t1 < Milisecond_Delay ; t1++)
for(double t2= 0 ; t2 < Milisecond; t2++);
}
void IM_Loader::run()
{
QString PATH = "/home/parsa/QtProjects/FINAL_VLPR/LowSpeed/";//Dataset_PATH;
//while(1)
{
for(float i = 0 ; i < 1 ; i++)
{
QString Folder_Address = PATH + QString::number((int)i)+"/";
QDir Mydir(Folder_Address);
Mydir.setFilter(QDir::Files);
QFileInfoList Vehicles_list = Mydir.entryInfoList();
qDebug()<<"Address is: "<<Folder_Address<<"\n";
qDebug()<<"Number of images are: "<<Vehicles_list.size()<<"\n";
static int overall_counter = 0; //12451
for(int j = 0 ; j < 300 ; j++)
{
if(!Stop_Disp)
{
QString address = Folder_Address + QString::number(overall_counter++) +".jpg";
cv::Mat image = cv::imread(address.toUtf8().constData(),0);
Delay(100);
if(!image.data)
{
qDebug()<<"Image Data is failed ... \n";
continue;
}
if(j%100==0)
qDebug()<<"Folder "<<i<<" Image No. "<<j<<" is processed, Overall counter is: "<<overall_counter<<"\n";
cv::Mat Dataaa;
image.copyTo(Dataaa);
QMutexLocker Locker(&Global_Mutex);
PD_Classifier_VEC.push_back(Dataaa);
Locker.unlock();
}
}
}
}
qDebug("Im loader is exited now ...");
}
adicionar um atraso de 100 ms reduziu o vazamento de memória para apenas 100 Mega Bytes em vez de 1 Gigabyte!!!
Solução
Finalmente descobri o que causou esse vazamento de memória...como você pode ver na classe im_loader e especificamente na função run(), tenho este bloco de código:
cv::Mat Dataaa;
image.copyTo(Dataaa);
QMutexLocker Locker(&Global_Mutex);
PD_Classifier_VEC.push_back(Dataaa);
Locker.unlock();
Como o OpenCV usa um procedimento de contagem de referência para o objeto cv::Mat, a imagem de entrada é copiada para a variável Dataa e depois para PD_Classifier.PD_Classifier é excluído, mas Dataa não!então, quando removi esta linha e alterei o código para este, o problema foi resolvido:
QMutexLocker Locker(&Global_Mutex);
PD_Classifier_VEC.push_back(image);
Locker.unlock();
Achei que, como Dataa é uma variável local, ela será excluída após sair da função run(), mas parece que, embora seja excluída após sair da função, seus dados permanecem na memória.