2017-03-21 30 views
1

Win7では、mingw-64ツールチェーンを使用したmsys2(Linux gcc上でも同じことが起こります)、OpenCv-3.2.0(ただし3.1.0 )。ここでスレッド中のOpenCv 3.2.0でのメモリリーク

は、私は私の問題を示すために、可能な限り簡素化しようとしたコードです:私はopencvDetector->process(img);直接呼び出す場合

#ifndef WL_DS_OPENCVDETECTOR_H 
#define WL_DS_OPENCVDETECTOR_H 

#include <string> 
#include <opencv2/opencv.hpp> 

namespace wl { 
namespace ds { 


class OpencvDetector { 
private: 
    cv::CascadeClassifier cascadeClassifier; 
public: 
    OpencvDetector() { cascadeClassifier.load("haarcascade_frontalface.xml"); }; 
    void process(cv::Mat img) { 
    cv::cvtColor(img, img, CV_BGR2GRAY); 
    cv::equalizeHist(img, img); 
    std::vector<cv::Rect> faces; 
    cascadeClassifier.detectMultiScale(img, faces, 1.05, 3, 0|CV_HAAR_SCALE_IMAGE); 
    }; 
}; 

} // wl 
} // ds 

#endif // WL_DS_OPENCVDETECTOR_H 

#include <thread> 
#include <iostream> 
#include <iomanip> 

#include "opencv_detector.h" 
#include <windows.h> 
#include <psapi.h> 

/** 
* Returns the current resident set size (physical memory use) measured in bytes 
*/ 
inline size_t getCurrentRSS() 
{ 
    PROCESS_MEMORY_COUNTERS info; 
    GetProcessMemoryInfo(GetCurrentProcess(), &info, sizeof(info)); 
    return (size_t)info.WorkingSetSize; 
} 

int main(int argc, char** argv) 
{ 
    auto opencvDetector = new wl::ds::OpencvDetector(); 
    cv::Mat img = cv::imread("./test.png"); 
    int i = 0; 
    long rss = getCurrentRSS(); 
    long rss_start = rss; 
    long rss1 = rss; 
    std::cout << std::setw(7) << "START " << rss <<std::endl; 
    while(i++<1000) { 
    // If I just call the function no memory leak 
    //opencvDetector->process(img); 
    // If I call the function in a thread, memory leak 
    auto opencvDetectProfile = std::thread(&wl::ds::OpencvDetector::process, opencvDetector, img); 
    opencvDetectProfile.join(); 

    rss1 = getCurrentRSS(); 
    if(rss!=rss1) { 
     std::cout << std::setw(6) << i << " " << rss1 << " (" << std::setw(8) << (rss1-rss) << "/" << std::setw(7) << (rss1-rss_start) << ")" << std::endl; 
     rss = rss1; 
    } 
    } 
    std::cout << std::setw(7) << "STOP " << rss1 << " (" << std::setw(8) << (rss1-rss) << "/" << std::setw(7) << (rss1-rss_start) << ")" << std::endl; 
    return 0; 
} 

、ここでは、非常に単純なopenCvDetectorクラスですメモリ使用量が急速に安定します。

START 18280448 
    1 30892032 (12611584/12611584) 
    2 30908416 ( 16384/12627968) 
    4 30928896 ( 20480/12648448) 
    5 30941184 ( 12288/12660736) 
    8 30945280 ( 4096/12664832) 
    11 30953472 ( 8192/12673024) 
    12 30957568 ( 4096/12677120) 
    STOP 30957568 (  0/12677120) 

ただし、 nはスレッド・バージョン(OpenCvDetectorのメンバ関数がスレッドで呼び出される)、メモリ使用量が増え続けて:私はたくさんのスレッドでOpenCVの検出の多くを達成したいので

START 18280448      
    1 30965760 (12685312/12685312) 
    2 30879744 ( -86016/12599296) 
    3 30883840 ( 4096/12603392) 
    8 30916608 ( 32768/12636160) 
    10 31035392 ( 118784/12754944) 
    11 31047680 ( 12288/12767232) 
    12 30961664 ( -86016/12681216) 
    14 30965760 ( 4096/12685312) 
    20 30969856 ( 4096/12689408) 
    120 31346688 ( 376832/13066240) 
    121 31084544 (-262144/12804096) 
    153 31088640 ( 4096/12808192) 
    213 31092736 ( 4096/12812288) 
    233 31096832 ( 4096/12816384) 
    248 31100928 ( 4096/12820480) 
    294 31105024 ( 4096/12824576) 
    335 31109120 ( 4096/12828672) 
    417 31113216 ( 4096/12832768) 
    499 31117312 ( 4096/12836864) 
    504 31121408 ( 4096/12840960) 
    540 31125504 ( 4096/12845056) 
    581 31129600 ( 4096/12849152) 
    665 31133696 ( 4096/12853248) 
    749 31137792 ( 4096/12857344) 
    781 31141888 ( 4096/12861440) 
    833 31145984 ( 4096/12865536) 
    848 31207424 ( 61440/12926976) 
STOP 31207424 (  0/12926976) 

は、私は失望しています、だから少しのメモリリークが急速にリソースの巨大な浪費になっているようです。 ヒントをいただければ幸いです...

答えて

0

すべてのスレッドで同じopencvDetectorを使用していると、未定義の動作につながる可能性があります。あなたのケースでは、それはメモリリークを引き起こしています。

この方法を試してみてください:

auto opencvDetector = new wl::ds::OpencvDetector(); 
auto opencvDetectProfile = std::thread(&wl::ds::OpencvDetector::process, opencvDetector, img); 
opencvDetectProfile.join(); 
delete opencvDetector; 
+0

こんにちはラーマ。私が間違っている場合、opencvdetectorの単一インスタンス自体に問題はありません。問題はCascadeClassifierの単一インスタンスの使用に関連していますか?私は明日の朝にそれを試さなければならないが、カスケードを読み込むことは非常に軽いものではないので、迷惑になるだろう。 – VirgileD

+0

とにかく、新しい道を探検してくれてありがとう! スレッドごとにスレッドに参加するときに、これがどのように問題になるかは分かりませんが、問題があるかどうかはまだ分かりません。 – VirgileD

+0

こんにちは@Rama。他の複数のテストの後、あなたのソリューションが私のニーズに合っていなくても(メモリの代わりにパフォーマンスを落とすような)、あなたは正しいと思います。複数の同じcv :: CascadeClassifierでdetectMultiScaleを呼び出すことはできませんスレッド(特にここに記載されています:https://github.com/opencv/opencv/issues/4287)。 – VirgileD

0

私はOpenCVに慣れていませんが、私自身のコードではメモリリークに精通しています。 Valgrindでトラブルシューティングを試みましたか?このツールは、通常、漏れやメモリの問題がどこにあるかを見つけるのに役立ちます。私は通常、分析を見ると、問題の99%を見つけます。

+0

こんにちはキース、提案に感謝します。私は数日間Windowsに固執していますが、Linuxの箱を手に入れようとするときに試してみましょう。私はデバッグフラグを使ってOpencvをコンパイルしなければならないと思いますが... – VirgileD

+0

OpenCVをコンパイルする必要はないかもしれません。 Valgrindは、関数やライブラリに問題があるとしばしば、変数、ファイル、行番号などのことを知らない場合があります。それが価値があることも知っています。 –

関連する問題