OpenCV의 거대한 메모리 누수
-
21-12-2019 - |
문제
다중 스레드 코드에서 600 개의 비디오 프레임을 읽는 매우 간단한 C ++ 프로그램을 작성했습니다. 문제는이 프레임 각각을 해제 할 때 자유 메모리 크기가 변경되지 않습니다! Qt 4.8 및 Ubuntu 12.04를 사용하고 있습니다 내 랩톱 메모리 크기는 8GB이므로 메모리 부족이 없습니다.
각 프레임은 1.8MB이므로 전체 크기는 600 * 1.8 MB= 1080MB
프로그램을 실행하기 전에 My Memory Free 크기는 6.8GB이지만 코드를 실행 한 후에는 Free Memory 크기가 5.9GB이므로 프로그램에 거대한 메모리 누수가 있습니다. 나는 코드를 1000 번 달리고 프로그램이 충돌하거나 문제에 직면하지 못하게 결코 코드가 괜찮습니다.
내 코드 :
#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
.
mainwindow.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;
}
.
mainwindow.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
.
definitions.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
.
OpenCV C ++ 버전이 메모리 관리를 지원하는 일부 기사에서 우리는 메모리 누수에 대해 걱정할 필요가 없습니다.
여기에 뭔가를 놓치고 있습니까? 나는이 질문들도 읽었지 만 그들 중 누구도 나를 위해 일하지 않았습니다. 이 및 이
나 한 게시물만이 나의 코드 에서이 문제가 있으면 내가 알아낼 수 없었습니다. 이것은 링크
필요한 경우 다른 것을 제공 할 것입니다.
편집 :
매우 흥미 롭습니다. 각 프레임을 읽은 직후에 ImageLoader 클래스에서 지연 기능을 추가하면 메모리 누수의 양이 줄어 듭니다 !!!
내 새로운 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 ...");
}
.
100ms 지연을 추가하면 메모리 누설이 1 기가 바이트 대신 100 메가 바이트로 축소되었습니다 !!!
해결책
마지막으로,이 메모리 누수가 발생한 내용을 알아 냈습니다. im_loader 클래스에서 볼 수 있으며 특별히 실행 () 함수는 다음 코드 블록을 가지고 있습니다.
cv::Mat Dataaa;
image.copyTo(Dataaa);
QMutexLocker Locker(&Global_Mutex);
PD_Classifier_VEC.push_back(Dataaa);
Locker.unlock();
.
opencv는 cv :: mat 객체에 대한 참조 카운팅 절차를 사용하기 때문에 입력 이미지가 DataA 변수에 복사 된 다음 pd_classifier로 복사됩니다.PD_CLASSIFIER 삭제되지만 DataA No!그래서이 선을 삭제하고 코드를 변경하면 문제가 해결되었습니다.
QMutexLocker Locker(&Global_Mutex);
PD_Classifier_VEC.push_back(image);
Locker.unlock();
.
DataA는 run () 함수를 종료 한 후 삭제할 것으로 밝혀 지지만 함수를 종료 한 후 삭제되지만 데이터가 메모리에 유지되는 것으로 나타났습니다.