3

私はこれを 1 か月間デバッグしようとしてきましたが、確かに私のプログラミングのやり方がまずかったのですが、バグかもしれないと思うので、報告する前にまずここで質問します。

次のコードを検討してください。

#include <sys/resource.h> // memory management.
#include <stdio.h>
#include <iostream>
#include <iomanip>

#include "opencv2/highgui/highgui.hpp"
#include "opencv2/core/core.hpp"
#include "opencv2/imgproc/imgproc.hpp"
#include "opencv2/video/background_segm.hpp"

using namespace std;
using namespace cv;

// Load frame from disk.
void readFrame(int frameNum, Mat &frame) {
    // Construct filenames
    Mat image;
    stringstream number, filename;

    number << setw(7) << setfill('0') << frameNum; // expecting over 1e10 images over the installation period.
    filename << "../images/store-" << number.str() << ".jpg"; // assumes jpegs!//
    cout << "Loading filename: " << filename.str() << endl;

    image = imread( filename.str() );

    if (image.empty() or !image.data) {
        cout << "Input image empty:\n";
    }

    frame = image.clone();
}

// Class to hold the perceptual chunks.
class percepUnit {

    public:
        cv::Mat image; // percept itself
        cv::Mat mask; // alpha channel

        // constructor method
        percepUnit(cv::Mat &ROI, cv::Mat &alpha, int ix, int iy, int iw, int ih, int area)  {
            image = ROI.clone();
            mask = alpha.clone();
        }
};

// Segment foreground from background
void segmentForeground(list<percepUnit*> &percepUnitsForeground, Mat &foreground, Mat &frame) {
    Mat contourImage = Mat(foreground.rows, foreground.cols, CV_8UC1, Scalar::all(0));
    vector<vector<Point>> contours;
    int area;

    // The following causes strange spikes in memory usage:
    // find contours
    findContours(foreground, contours, CV_RETR_EXTERNAL, CV_CHAIN_APPROX_SIMPLE);

    for (int idx = 0; idx < contours.size(); idx++) {

        area = contourArea(contours[idx]);

        if (area > 100) {

            percepUnit *thisUnit = new percepUnit(frame, contourImage, 0, 0, 100,100, area);
            percepUnitsForeground.push_back(thisUnit); // Append to percepUnits
        }
    }

    /* The following does not:
    findContours(foreground, contours, CV_RETR_EXTERNAL, CV_CHAIN_APPROX_SIMPLE);

    for (int idx = 0; idx < contours.size(); idx++) {
        area = contourArea(contours[idx]);
    }*/

    /* Neither does this:
    for (int idx = 0; idx < 10; idx++) {
        percepUnit *thisUnit = new percepUnit(frame, contourImage, 0, 0, 100,100, area);
        percepUnitsForeground.push_back(thisUnit); // Append to percepUnits
    }*/
}

int main(int argc, const char** argv)
{
    int frameCount = 78298; 
    Mat frame, foreground;
    BackgroundSubtractorMOG2 MOG2model;
    list<percepUnit*> scratchPercepUnitsForeground;

    // add rusage stuff
    struct rusage usage; // memory usage.

    for(int i=0; i<= 75; i++)
    {
        // run full segmenter here.  (background disabled)

        readFrame(frameCount, frame); // was frame = readFrame();

        // Only process if this frame actually loaded (non empty)
        if ( not frame.empty() ) {

            MOG2model(frame,foreground); // Update MOG2 model, downscale?

            // before we segment again clear scratch
            // TODO how to delete the actual memory allocated? Run delete on everything?
            for (list<percepUnit*>::iterator percepIter = scratchPercepUnitsForeground.begin(); 
                 percepIter != scratchPercepUnitsForeground.end();
                 percepIter++) {

                delete *percepIter; // delete what we point to.
                //percepIter = scratchPercepUnitsForeground.erase(percepIter); // remove the pointer itself, and update the iterator.
            }
            // Added with EDIT1
            scratchPercepUnitsForeground.clear();

            // Segment the foreground regions and generate boolImage to extract from background.
            segmentForeground(scratchPercepUnitsForeground, foreground, frame);

        }

        frameCount++;

        getrusage(RUSAGE_SELF, &usage);
        cout << "DEBUG leakTest_bug_report " << i << " " << usage.ru_maxrss/1024.0 << endl;
    }

    return 0;
}

ここ ( http://www.ekran.org/tmp/images.tar.gz ) で入手できる画像を使用すると、プログラムのメモリ使用量が増加し、前景の輪郭の数とともに増加するように見えることがわかります。フレームごとにストレージ (scratchPercepUnitsForeground) をクリアしているので、メモリ使用量が増える理由がわかりません。segmentForeground() 関数は、フレームごとに、使用されているすべてのメモリの割り当てを解除して終了する必要があります。関数が終了した後にのみメモリ使用量をチェックするため、メモリ使用量は時間の経過とともに一定である必要があります。わからないものが残っているようです。

percepUnit() コンストラクターを使用せずに findContours() 部分だけを実行すると、予想どおり、メモリ使用量は一定です。findContours() を使用せずに percepUnit() コンストラクターのみを実行すると、メモリ使用量は一定になります。両方を使用した場合にのみメモリ使用量が増加します。上記の segmentForeground() のコメント付きコードを参照してください。

2 台のマシン (AMD64、Linux の両方) でこの問題を確認し、opencv 2.4.6.1 と 2.4.5 を実行しています。

編集1

上記のコードは、以下の提案を含むように変更されましたが、それでも問題は解決しません。

メモリの増加は次のようになります。

メモリ使用量
(ソース: ekran.org )

赤い線は、findContours() とコンストラクターの両方が呼び出されたときに見られるメモリの増加です (上記のリンクのテスト イメージと相関しています) 以下の安定した行は、findContours() またはコンストラクターのいずれかを実行する 2 つのケースです。

Valgrind 出力

==2055== Memcheck, a memory error detector
==2055== Copyright (C) 2002-2011, and GNU GPL'd, by Julian Seward et al.
==2055== Using Valgrind-3.7.0 and LibVEX; rerun with -h for copyright info
==2055== Command: ./leakTest
==2055== 
==2055== 
==2055== HEAP SUMMARY:
==2055==     in use at exit: 217,751,704 bytes in 112 blocks
==2055==   total heap usage: 800,066 allocs, 799,954 frees, 29,269,767,865 bytes allocated
==2055== 
==2055== 568 bytes in 1 blocks are still reachable in loss record 1 of 12
==2055==    at 0x4C2B6CD: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==2055==    by 0x63A720A: __fopen_internal (iofopen.c:76)
==2055==    by 0xA8BC050: libjpeg_general_init (in /usr/lib/x86_64-linux-gnu/libjpeg.so.8.0.2)
==2055==    by 0x400F305: call_init.part.0 (dl-init.c:85)
==2055==    by 0x400F3DE: _dl_init (dl-init.c:52)
==2055==    by 0x40016E9: ??? (in /lib/x86_64-linux-gnu/ld-2.15.so)
==2055== 
==2055== 2,072 bytes in 1 blocks are still reachable in loss record 2 of 12
==2055==    at 0x4C2B6CD: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==2055==    by 0x1495F675: ??? (in /usr/lib/x86_64-linux-gnu/libpixman-1.so.0.24.4)
==2055==    by 0x1495E4AE: ??? (in /usr/lib/x86_64-linux-gnu/libpixman-1.so.0.24.4)
==2055==    by 0x14950888: ??? (in /usr/lib/x86_64-linux-gnu/libpixman-1.so.0.24.4)
==2055==    by 0x149253B8: ??? (in /usr/lib/x86_64-linux-gnu/libpixman-1.so.0.24.4)
==2055==    by 0x400F305: call_init.part.0 (dl-init.c:85)
==2055==    by 0x400F3DE: _dl_init (dl-init.c:52)
==2055==    by 0x40016E9: ??? (in /lib/x86_64-linux-gnu/ld-2.15.so)
==2055== 
==2055== 2,072 bytes in 1 blocks are still reachable in loss record 3 of 12
==2055==    at 0x4C2B6CD: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==2055==    by 0x1495F675: ??? (in /usr/lib/x86_64-linux-gnu/libpixman-1.so.0.24.4)
==2055==    by 0x1495E0EF: ??? (in /usr/lib/x86_64-linux-gnu/libpixman-1.so.0.24.4)
==2055==    by 0x14950890: ??? (in /usr/lib/x86_64-linux-gnu/libpixman-1.so.0.24.4)
==2055==    by 0x149253B8: ??? (in /usr/lib/x86_64-linux-gnu/libpixman-1.so.0.24.4)
==2055==    by 0x400F305: call_init.part.0 (dl-init.c:85)
==2055==    by 0x400F3DE: _dl_init (dl-init.c:52)
==2055==    by 0x40016E9: ??? (in /lib/x86_64-linux-gnu/ld-2.15.so)
==2055== 
==2055== 2,072 bytes in 1 blocks are still reachable in loss record 4 of 12
==2055==    at 0x4C2B6CD: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==2055==    by 0x1495F675: ??? (in /usr/lib/x86_64-linux-gnu/libpixman-1.so.0.24.4)
==2055==    by 0x14971A6F: ??? (in /usr/lib/x86_64-linux-gnu/libpixman-1.so.0.24.4)
==2055==    by 0x14950898: ??? (in /usr/lib/x86_64-linux-gnu/libpixman-1.so.0.24.4)
==2055==    by 0x149253B8: ??? (in /usr/lib/x86_64-linux-gnu/libpixman-1.so.0.24.4)
==2055==    by 0x400F305: call_init.part.0 (dl-init.c:85)
==2055==    by 0x400F3DE: _dl_init (dl-init.c:52)
==2055==    by 0x40016E9: ??? (in /lib/x86_64-linux-gnu/ld-2.15.so)
==2055== 
==2055== 2,072 bytes in 1 blocks are still reachable in loss record 5 of 12
==2055==    at 0x4C2B6CD: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==2055==    by 0x1495F675: ??? (in /usr/lib/x86_64-linux-gnu/libpixman-1.so.0.24.4)
==2055==    by 0x1499024F: ??? (in /usr/lib/x86_64-linux-gnu/libpixman-1.so.0.24.4)
==2055==    by 0x149508A0: ??? (in /usr/lib/x86_64-linux-gnu/libpixman-1.so.0.24.4)
==2055==    by 0x149253B8: ??? (in /usr/lib/x86_64-linux-gnu/libpixman-1.so.0.24.4)
==2055==    by 0x400F305: call_init.part.0 (dl-init.c:85)
==2055==    by 0x400F3DE: _dl_init (dl-init.c:52)
==2055==    by 0x40016E9: ??? (in /lib/x86_64-linux-gnu/ld-2.15.so)
==2055== 
==2055== 2,072 bytes in 1 blocks are still reachable in loss record 6 of 12
==2055==    at 0x4C2B6CD: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==2055==    by 0x1495F675: ??? (in /usr/lib/x86_64-linux-gnu/libpixman-1.so.0.24.4)
==2055==    by 0x149610EF: ??? (in /usr/lib/x86_64-linux-gnu/libpixman-1.so.0.24.4)
==2055==    by 0x149253B8: ??? (in /usr/lib/x86_64-linux-gnu/libpixman-1.so.0.24.4)
==2055==    by 0x400F305: call_init.part.0 (dl-init.c:85)
==2055==    by 0x400F3DE: _dl_init (dl-init.c:52)
==2055==    by 0x40016E9: ??? (in /lib/x86_64-linux-gnu/ld-2.15.so)
==2055== 
==2055== 4,096 bytes in 1 blocks are still reachable in loss record 7 of 12
==2055==    at 0x4C2B6CD: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==2055==    by 0xA8BC067: libjpeg_general_init (in /usr/lib/x86_64-linux-gnu/libjpeg.so.8.0.2)
==2055==    by 0x400F305: call_init.part.0 (dl-init.c:85)
==2055==    by 0x400F3DE: _dl_init (dl-init.c:52)
==2055==    by 0x40016E9: ??? (in /lib/x86_64-linux-gnu/ld-2.15.so)
==2055== 
==2055== 1,555,228 bytes in 1 blocks are possibly lost in loss record 8 of 12
==2055==    at 0x4C2B6CD: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==2055==    by 0x4E87A90: cv::fastMalloc(unsigned long) (in /usr/local/lib/libopencv_core.so.2.4.5)
==2055==    by 0x4ECDBF1: cv::Mat::create(int, int const*, int) (in /usr/local/lib/libopencv_core.so.2.4.5)
==2055==    by 0x4ECE378: cv::_OutputArray::create(int, int, int, int, bool, int) const (in /usr/local/lib/libopencv_core.so.2.4.5)
==2055==    by 0x4F52F7D: cv::Mat::copyTo(cv::_OutputArray const&) const (in /usr/local/lib/libopencv_core.so.2.4.5)
==2055==    by 0x40253C: cv::Mat::clone() const (mat.hpp:335)
==2055==    by 0x4028D5: percepUnit::percepUnit(cv::Mat&, cv::Mat&, int, int, int, int, int) (leakTest.cpp:43)
==2055==    by 0x401E0E: segmentForeground(std::list<percepUnit*, std::allocator<percepUnit*> >&, cv::Mat&, cv::Mat&) (leakTest.cpp:63)
==2055==    by 0x40202D: main (leakTest.cpp:114)
==2055== 
==2055== 37,325,024 bytes in 8 blocks are possibly lost in loss record 9 of 12
==2055==    at 0x4C2B6CD: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==2055==    by 0x4E87A90: cv::fastMalloc(unsigned long) (in /usr/local/lib/libopencv_core.so.2.4.5)
==2055==    by 0x4ECDBF1: cv::Mat::create(int, int const*, int) (in /usr/local/lib/libopencv_core.so.2.4.5)
==2055==    by 0x4ECE378: cv::_OutputArray::create(int, int, int, int, bool, int) const (in /usr/local/lib/libopencv_core.so.2.4.5)
==2055==    by 0x4F52F7D: cv::Mat::copyTo(cv::_OutputArray const&) const (in /usr/local/lib/libopencv_core.so.2.4.5)
==2055==    by 0x40253C: cv::Mat::clone() const (mat.hpp:335)
==2055==    by 0x402897: percepUnit::percepUnit(cv::Mat&, cv::Mat&, int, int, int, int, int) (leakTest.cpp:42)
==2055==    by 0x401E0E: segmentForeground(std::list<percepUnit*, std::allocator<percepUnit*> >&, cv::Mat&, cv::Mat&) (leakTest.cpp:63)
==2055==    by 0x40202D: main (leakTest.cpp:114)
==2055== 
==2055== 52,877,752 bytes in 34 blocks are indirectly lost in loss record 10 of 12
==2055==    at 0x4C2B6CD: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==2055==    by 0x4E87A90: cv::fastMalloc(unsigned long) (in /usr/local/lib/libopencv_core.so.2.4.5)
==2055==    by 0x4ECDBF1: cv::Mat::create(int, int const*, int) (in /usr/local/lib/libopencv_core.so.2.4.5)
==2055==    by 0x4ECE378: cv::_OutputArray::create(int, int, int, int, bool, int) const (in /usr/local/lib/libopencv_core.so.2.4.5)
==2055==    by 0x4F52F7D: cv::Mat::copyTo(cv::_OutputArray const&) const (in /usr/local/lib/libopencv_core.so.2.4.5)
==2055==    by 0x40253C: cv::Mat::clone() const (mat.hpp:335)
==2055==    by 0x4028D5: percepUnit::percepUnit(cv::Mat&, cv::Mat&, int, int, int, int, int) (leakTest.cpp:43)
==2055==    by 0x401E0E: segmentForeground(std::list<percepUnit*, std::allocator<percepUnit*> >&, cv::Mat&, cv::Mat&) (leakTest.cpp:63)
==2055==    by 0x40202D: main (leakTest.cpp:114)
==2055== 
==2055== 125,971,956 bytes in 27 blocks are indirectly lost in loss record 11 of 12
==2055==    at 0x4C2B6CD: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==2055==    by 0x4E87A90: cv::fastMalloc(unsigned long) (in /usr/local/lib/libopencv_core.so.2.4.5)
==2055==    by 0x4ECDBF1: cv::Mat::create(int, int const*, int) (in /usr/local/lib/libopencv_core.so.2.4.5)
==2055==    by 0x4ECE378: cv::_OutputArray::create(int, int, int, int, bool, int) const (in /usr/local/lib/libopencv_core.so.2.4.5)
==2055==    by 0x4F52F7D: cv::Mat::copyTo(cv::_OutputArray const&) const (in /usr/local/lib/libopencv_core.so.2.4.5)
==2055==    by 0x40253C: cv::Mat::clone() const (mat.hpp:335)
==2055==    by 0x402897: percepUnit::percepUnit(cv::Mat&, cv::Mat&, int, int, int, int, int) (leakTest.cpp:42)
==2055==    by 0x401E0E: segmentForeground(std::list<percepUnit*, std::allocator<percepUnit*> >&, cv::Mat&, cv::Mat&) (leakTest.cpp:63)
==2055==    by 0x40202D: main (leakTest.cpp:114)
==2055== 
==2055== 178,856,428 (6,720 direct, 178,849,708 indirect) bytes in 35 blocks are definitely lost in loss record 12 of 12
==2055==    at 0x4C2B1C7: operator new(unsigned long) (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==2055==    by 0x401DD3: segmentForeground(std::list<percepUnit*, std::allocator<percepUnit*> >&, cv::Mat&, cv::Mat&) (leakTest.cpp:63)
==2055==    by 0x40202D: main (leakTest.cpp:114)
==2055== 
==2055== LEAK SUMMARY:
==2055==    definitely lost: 6,720 bytes in 35 blocks
==2055==    indirectly lost: 178,849,708 bytes in 61 blocks
==2055==      possibly lost: 38,880,252 bytes in 9 blocks
==2055==    still reachable: 15,024 bytes in 7 blocks
==2055==         suppressed: 0 bytes in 0 blocks
==2055== 
==2055== For counts of detected and suppressed errors, rerun with: -v
==2055== ERROR SUMMARY: 3 errors from 3 contexts (suppressed: 2 from 2)

したがって、基本的にこれは、clone() を実行する percepUnit コンストラクターに問題がある可能性があることを示しているようです。findContours() なしでコンストラクターを実行しても、(前述のように) メモリの増加は見られません。これには、「new」の使用が含まれます。jpeg リーダーも単体テスト済みで、メモリの増加はありません。そのため、valgrind の出力はまったく役に立たないようです。

これは再現できるはずです!回答を提供する前に、再現できることを確認してください。

EDIT2 (修正されたコードと valgrind 出力、削除されたポインター メソッド)

ここでは、リストをポインターのリストからインスタンスのリストに変更しました。メモリの増加が確認されました。

#include <sys/resource.h> // memory management.
#include <stdio.h>
#include <iostream>
#include <iomanip>

#include "opencv2/highgui/highgui.hpp"
#include "opencv2/core/core.hpp"
#include "opencv2/imgproc/imgproc.hpp"
#include "opencv2/video/background_segm.hpp"

using namespace std;
using namespace cv;

// Load frame from disk.
void readFrame(int frameNum, Mat &frame) {
    // Construct filenames
    Mat image;
    stringstream number, filename;

    number << setw(7) << setfill('0') << frameNum; // expecting over 1e10 images over the installation period.
    filename << "../images/store-" << number.str() << ".jpg"; // assumes jpegs!//
    cout << "Loading filename: " << filename.str() << endl;

    image = imread( filename.str() );

    if (image.empty() or !image.data) {
        cout << "Input image empty:\n";
    }

    frame = image.clone();
}

// Class to hold the perceptual chunks.
class percepUnit {
    
    public:
        cv::Mat image; // percept itself
        cv::Mat mask; // alpha channel
        
        // constructor method
        percepUnit(cv::Mat &ROI, cv::Mat &alpha, int ix, int iy, int iw, int ih, int area)  {
            image = ROI.clone();
            mask = alpha.clone();
        }
};

// Segment foreground from background
void segmentForeground(list<percepUnit> &percepUnitsForeground, Mat &foreground, Mat &frame) {
    Mat contourImage = Mat(foreground.rows, foreground.cols, CV_8UC1, Scalar::all(0));
    vector<vector<Point>> contours;
    int area;

    // The following causes strange spikes in memory usage:
    // find contours
    findContours(foreground, contours, CV_RETR_EXTERNAL, CV_CHAIN_APPROX_SIMPLE);

    for (int idx = 0; idx < contours.size(); idx++) {

        area = contourArea(contours[idx]);

        if (area > 100) {

            percepUnit thisUnit = percepUnit(frame, contourImage, 0, 0, 100,100, area);
            percepUnitsForeground.push_back(thisUnit); // Append to percepUnits
        }
    }

    /* The following does not:
    findContours(foreground, contours, CV_RETR_EXTERNAL, CV_CHAIN_APPROX_SIMPLE);

    for (int idx = 0; idx < contours.size(); idx++) {
        area = contourArea(contours[idx]);
    }*/

    /* Neither does this:
    for (int idx = 0; idx < 10; idx++) {
        percepUnit thisUnit = percepUnit(frame, contourImage, 0, 0, 100,100, area);
        percepUnitsForeground.push_back(thisUnit); // Append to percepUnits
    }*/
}

int main(int argc, const char** argv)
{
    int frameCount = 78298; 
    Mat frame, foreground;
    BackgroundSubtractorMOG2 MOG2model;
    list<percepUnit> scratchPercepUnitsForeground;

    // add rusage stuff
    struct rusage usage; // memory usage.

    for(int i=0; i<= 75; i++)
    {
        // run full segmenter here.  (background disabled)
        
        readFrame(frameCount, frame); // was frame = readFrame();

        // Only process if this frame actually loaded (non empty)
        if ( not frame.empty() ) {

            MOG2model(frame,foreground); // Update MOG2 model, downscale?

            // before we segment again clear scratch
            scratchPercepUnitsForeground.clear();
    
            // Segment the foreground regions and generate boolImage to extract from background.
            segmentForeground(scratchPercepUnitsForeground, foreground, frame);

        }

        frameCount++;

        getrusage(RUSAGE_SELF, &usage);
        cout << "DEBUG leakTest_bug_report " << i << " " << usage.ru_maxrss/1024.0 << endl;
    }

    return 0;
}

対応する valgrind 出力は次のとおりです。

==3562== Memcheck, a memory error detector
==3562== Copyright (C) 2002-2011, and GNU GPL'd, by Julian Seward et al.
==3562== Using Valgrind-3.7.0 and LibVEX; rerun with -h for copyright info
==3562== Command: ./leakTest
==3562== 
==3562== 
==3562== HEAP SUMMARY:
==3562==     in use at exit: 15,024 bytes in 7 blocks
==3562==   total heap usage: 795,556 allocs, 795,549 frees, 29,269,731,785 bytes allocated
==3562== 
==3562== 568 bytes in 1 blocks are still reachable in loss record 1 of 7
==3562==    at 0x4C2B6CD: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==3562==    by 0x63A720A: __fopen_internal (iofopen.c:76)
==3562==    by 0xA8BC050: libjpeg_general_init (in /usr/lib/x86_64-linux-gnu/libjpeg.so.8.0.2)
==3562==    by 0x400F305: call_init.part.0 (dl-init.c:85)
==3562==    by 0x400F3DE: _dl_init (dl-init.c:52)
==3562==    by 0x40016E9: ??? (in /lib/x86_64-linux-gnu/ld-2.15.so)
==3562== 
==3562== 2,072 bytes in 1 blocks are still reachable in loss record 2 of 7
==3562==    at 0x4C2B6CD: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==3562==    by 0x1495F675: ??? (in /usr/lib/x86_64-linux-gnu/libpixman-1.so.0.24.4)
==3562==    by 0x1495E4AE: ??? (in /usr/lib/x86_64-linux-gnu/libpixman-1.so.0.24.4)
==3562==    by 0x14950888: ??? (in /usr/lib/x86_64-linux-gnu/libpixman-1.so.0.24.4)
==3562==    by 0x149253B8: ??? (in /usr/lib/x86_64-linux-gnu/libpixman-1.so.0.24.4)
==3562==    by 0x400F305: call_init.part.0 (dl-init.c:85)
==3562==    by 0x400F3DE: _dl_init (dl-init.c:52)
==3562==    by 0x40016E9: ??? (in /lib/x86_64-linux-gnu/ld-2.15.so)
==3562== 
==3562== 2,072 bytes in 1 blocks are still reachable in loss record 3 of 7
==3562==    at 0x4C2B6CD: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==3562==    by 0x1495F675: ??? (in /usr/lib/x86_64-linux-gnu/libpixman-1.so.0.24.4)
==3562==    by 0x1495E0EF: ??? (in /usr/lib/x86_64-linux-gnu/libpixman-1.so.0.24.4)
==3562==    by 0x14950890: ??? (in /usr/lib/x86_64-linux-gnu/libpixman-1.so.0.24.4)
==3562==    by 0x149253B8: ??? (in /usr/lib/x86_64-linux-gnu/libpixman-1.so.0.24.4)
==3562==    by 0x400F305: call_init.part.0 (dl-init.c:85)
==3562==    by 0x400F3DE: _dl_init (dl-init.c:52)
==3562==    by 0x40016E9: ??? (in /lib/x86_64-linux-gnu/ld-2.15.so)
==3562== 
==3562== 2,072 bytes in 1 blocks are still reachable in loss record 4 of 7
==3562==    at 0x4C2B6CD: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==3562==    by 0x1495F675: ??? (in /usr/lib/x86_64-linux-gnu/libpixman-1.so.0.24.4)
==3562==    by 0x14971A6F: ??? (in /usr/lib/x86_64-linux-gnu/libpixman-1.so.0.24.4)
==3562==    by 0x14950898: ??? (in /usr/lib/x86_64-linux-gnu/libpixman-1.so.0.24.4)
==3562==    by 0x149253B8: ??? (in /usr/lib/x86_64-linux-gnu/libpixman-1.so.0.24.4)
==3562==    by 0x400F305: call_init.part.0 (dl-init.c:85)
==3562==    by 0x400F3DE: _dl_init (dl-init.c:52)
==3562==    by 0x40016E9: ??? (in /lib/x86_64-linux-gnu/ld-2.15.so)
==3562== 
==3562== 2,072 bytes in 1 blocks are still reachable in loss record 5 of 7
==3562==    at 0x4C2B6CD: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==3562==    by 0x1495F675: ??? (in /usr/lib/x86_64-linux-gnu/libpixman-1.so.0.24.4)
==3562==    by 0x1499024F: ??? (in /usr/lib/x86_64-linux-gnu/libpixman-1.so.0.24.4)
==3562==    by 0x149508A0: ??? (in /usr/lib/x86_64-linux-gnu/libpixman-1.so.0.24.4)
==3562==    by 0x149253B8: ??? (in /usr/lib/x86_64-linux-gnu/libpixman-1.so.0.24.4)
==3562==    by 0x400F305: call_init.part.0 (dl-init.c:85)
==3562==    by 0x400F3DE: _dl_init (dl-init.c:52)
==3562==    by 0x40016E9: ??? (in /lib/x86_64-linux-gnu/ld-2.15.so)
==3562== 
==3562== 2,072 bytes in 1 blocks are still reachable in loss record 6 of 7
==3562==    at 0x4C2B6CD: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==3562==    by 0x1495F675: ??? (in /usr/lib/x86_64-linux-gnu/libpixman-1.so.0.24.4)
==3562==    by 0x149610EF: ??? (in /usr/lib/x86_64-linux-gnu/libpixman-1.so.0.24.4)
==3562==    by 0x149253B8: ??? (in /usr/lib/x86_64-linux-gnu/libpixman-1.so.0.24.4)
==3562==    by 0x400F305: call_init.part.0 (dl-init.c:85)
==3562==    by 0x400F3DE: _dl_init (dl-init.c:52)
==3562==    by 0x40016E9: ??? (in /lib/x86_64-linux-gnu/ld-2.15.so)
==3562== 
==3562== 4,096 bytes in 1 blocks are still reachable in loss record 7 of 7
==3562==    at 0x4C2B6CD: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==3562==    by 0xA8BC067: libjpeg_general_init (in /usr/lib/x86_64-linux-gnu/libjpeg.so.8.0.2)
==3562==    by 0x400F305: call_init.part.0 (dl-init.c:85)
==3562==    by 0x400F3DE: _dl_init (dl-init.c:52)
==3562==    by 0x40016E9: ??? (in /lib/x86_64-linux-gnu/ld-2.15.so)
==3562== 
==3562== LEAK SUMMARY:
==3562==    definitely lost: 0 bytes in 0 blocks
==3562==    indirectly lost: 0 bytes in 0 blocks
==3562==      possibly lost: 0 bytes in 0 blocks
==3562==    still reachable: 15,024 bytes in 7 blocks
==3562==         suppressed: 0 bytes in 0 blocks
==3562== 
==3562== For counts of detected and suppressed errors, rerun with: -v
==3562== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 2 from 2)

それでも、メモリは説明できないほど増加します: (前のプロットからの全体的な増加は、このテストを valgrind で実行したためです。)

メモリ使用量
(ソース: ekran.org )

同じコードのMassif 出力は次のとおりです: http://www.ekran.org/tmp/massif.print.leak findContours() が呼び出されず、percepUnit コンストラクターのみが呼び出される非リーク ケースの Massif 出力: http ://www.ekran.org/tmp/massif.print.noLeak

EDIT3

クロススレッド ( http://answers.opencv.org/question/19172/bug-increasing-memory-usage-per-iteration-when/ ) で、rusage メソッドを使用するのではなく proc を読むことが提案されました。これを見てください、メモリは着実に増加していません: (!)

メモリ使用量
(ソース: ekran.org )

これは、massif の出力と同じように見えます!! したがって、すべての単体テストをやり直す必要があると思います。私がここであきらめて問題を考えるべきではない理由がある人はいますか?

4

4 に答える 4

4

ptr-list クリーンアップの for ループpercepIter++は、ループ本体自体 (erase()呼び出しからの戻り値) にインクリメント節 () と反復子の再割り当ての両方があるため、項目をスキップしています。

つまり、イテレータを 2 倍に増やし、偶数スロットの項目をすべてスキップします。

以下にマークを付けました。

        for (list<percepUnit*>::iterator percepIter = scratchPercepUnitsForeground.begin(); 
             percepIter != scratchPercepUnitsForeground.end();
             percepIter++) { // ADVANCES ITERATOR

            delete *percepIter; // delete what we point to.
            percepIter = scratchPercepUnitsForeground.erase(percepIter); // ADVANCES ITERATOR
        }

これにはいくつかの方法で対処できます。たとえば、for ループからインクリメント式を削除すると、次のようになります。

       for (list<percepUnit*>::iterator percepIter = scratchPercepUnitsForeground.begin(); 
             percepIter != scratchPercepUnitsForeground.end();) {

            delete *percepIter; // delete what we point to.
            percepIter = scratchPercepUnitsForeground.erase(percepIter);
        }

clear()同様に、単純にリストを列挙し、ポイント先のオブジェクトをすべて解放したらlist メソッドを呼び出すことができます。

       for (list<percepUnit*>::iterator percepIter = scratchPercepUnitsForeground.begin(); 
             percepIter != scratchPercepUnitsForeground.end();
             ++percepIter) 
        {
            delete *percepIter;
        }
        scratchPercepUnitsForeground.clear();

個人的には、どちらかを選ばなければならない場合、後者が好きです。とりわけ、より高速で、より読みやすくなっています。

しかし、私がこれをコーディングするとしたら、スマート ポインターを使用することにscratchPercepUnitsForeground.clear();なります。リストの内容がクリアされると、すべてのスマート ポインター デストラクタが起動し、オブジェクトが削除されます。この概念は Resource Acquisition Is Initialization (略して RAII) と呼ばれ、動的割り当てを含むすべてのものにスコープベースの有効期間があり、スコープが終了するとリソースが自動的に再利用されることを意味します。詳細については、こちらをご覧ください

とにかく、それは間違いなく漏れがある場所であり、物事の見た目から判断すると大きなものです.

于 2013-08-21T00:20:14.237 に答える
2

私には、グラフのプロファイリングrusageが単調に増加するという事実が疑わしいです。

状態のドキュメントrusage:

使用される常駐セットの最大サイズ (キロバイト単位)。つまり、プロセスが同時に使用する物理メモリの最大キロバイト数です。

複数のイメージ間でのみ同じプロセスの統計を収集する可能性が高いため、すべてのイメージrusageの最大メモリ使用量を報告するという結論は理にかなっています。

実際、別のプロファイリング ツール (OS X のインストゥルメント) を使用すると、現在のメモリ使用量を示す次のグラフが生成されます。

メモリ割り当て

これは、 を使用した結果と非常によく似ていますprocrusageそれはあなたが望むプロファイリングツールではないと結論付けます。

于 2013-08-22T17:26:57.503 に答える
1

同じ問題と思われるものをグーグルで検索した後、この質問を見つけました(_dl_initとlibpixman-1を含むバックトレースで「まだ到達可能な」メモリを報告するvalgrind)。Fedora 18 64 ビットを使用しています。絶対に最小限のC実行可能ファイルと.soライブラリで問題を再現することができました... Cプログラムには0を返すmain関数だけがあり、.soには関数が1つだけあり(実際には呼び出されません)、これもすぐに終了します0. それでも valgrind は、合計 10,360 バイトの解放されていないブロックを 5 つ報告します。他の貧しい人々が同じ問題のデバッグに1か月を費やした場合に備えて、これを投稿することにしました! バグが何であれ、実行可能ファイルとライブラリが原因であるとは考えにくく、どちらも何もしません。

于 2013-10-31T01:08:53.387 に答える