1

私は OpenCV を使用しており、多数の画像 (Matオブジェクト) をベクターに格納したいと考えています。Matオブジェクトへのポインターを格納するために、次のようにベクトルを宣言しました。

std::vector<Mat*> images;

Matオブジェクトはキーワードを使用して作成さnewれ、ベクターに追加されます。

Mat *img = new Mat(height, width, CV_8UC3);
// set the values for the pixels here
images.push_back(img);

Matオブジェクトが占有しているメモリを確実に解放して、メモリ リークを回避するにはどうすればよいでしょうか。

私が今していることは次のとおりです。

Mat *im = images.at(index);
// process and display image here
delete(im);

Valgrind は、作成された Mat オブジェクトを参照してメモリ リークの可能性を報告しています。何か不足していますか?

編集:

Ok。どうやら、ポインタを使用したり、を使用して動的に割り当てたりすることは避けたほうがよいようMatです。代わりに使用するようにコードを変更しました。ただし、 Valgrind レポートで失われた可能性があるために割り当てられたいくつかのブロックがまだ表示されます。また、プログラムの実行中にメモリ使用量が着実に増加していることにも気付きました。Matnewstd::vector<Mat>Mat

私が何をしているのかを明確にしましょう。関数で画像を作成し、それらをバッファーに配置しています(内部的にを使用していますstd::deque)。このバッファは、別の関数によってアクセスされて取得およびイメージ化され、処理とレンダリングを実行する別の関数に渡されます。

class Render {
   public:
      void setImage(Mat& img) {
         this->image = img;
      }

      void render() {
         // process image and render here
      }
   private:
      Mat image;
}

バッファから画像を継続的にフェッチしてレンダリングするスレッド。

void* process(void *opaque) {

   ImageProcessor *imgProc = (ImageProcessor*) opaque;
   Mat img;


   while (imgProc->isRunning) {
      // get an image from the buffer
      imgProc->buffer->getFront(img);

      // set the image
      imgProc->renderer->setImage(img);

      // process and render
      imgProc->renderer->render();
   }

}

これで、すべてがオブジェクト参照 (つまりMat&) として渡されます。バッファから画像を取得してレンダリング関数に渡した後、そのオブジェクトへの唯一の参照がその関数内にあると仮定します。したがって、別の画像を取得すると、そのオブジェクトへの参照がなくなり、破棄されます。しかし、Valgrind は次のことを教えてくれます。

25,952,564 bytes in 11 blocks are possibly lost in loss record 14,852 of 14,853
  in ImageProcessor::generateImage() in ImageProcessor.cpp:393
  1: malloc in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so
  2: cv::fastMalloc(unsigned long) in /usr/local/lib/libopencv_core.so.2.4.2
  3: cv::Mat::create(int, int const*, int) in /usr/local/lib/libopencv_core.so.2.4.2
  4: cv::Mat::create(int, int, int) in /usr/local/include/opencv2/core/mat.hpp:353
  5: cv::Mat::Mat(int, int, int) in /usr/local/include/opencv2/core/mat.hpp:75
  ...

そしてここにあるgenerateImage()

void generateImage() {
   Mat img(h, w, CV_8UC3); 
   // set values of pixels here
   this->buffer->pushBack(img);
}
4

2 に答える 2

1

実際にオブジェクトを慎重に削除すれば、メモリ リークは発生しません。そうは言っても、人為的エラー (つまり、アプリケーションのまれなケースでオブジェクトを削除するのを忘れる) を起こしにくいベクトルにポインターを格納する方法があります。

C++11 を使用できる場合はstd::shared_ptr、生のポインターの代わりに使用することをお勧めします。これにより、オブジェクトを使用するコードがなくなったときにメモリが (自動的に) 削除されMatます。

ポインターの型を変更する必要がある以外に、他に変更を加える必要がないという利点もあります。通常のptr->memberおよび式も同様*ptrに有効です。std::shared_ptr

に関するドキュメントをstd::shared_ptr次に示します。また、特定のニーズに応じてstd::reference_wrapper、同様に検討することもできます。


編集: C++11 はオプションではないため、試すことができますboost::shared_ptr— 標準std::shared_ptrは Boost に基づいています。Boost もオプションでない場合は、独自の共有ポインターを実装できますが、それほど難しくありません。

プログラムのサイズは、別の考慮事項です。アプリケーションがかなり小さく、メモリ リークを引き起こす可能性のあるいくつかのまれなケースを忘れる可能性がほとんどない場合、これらすべてがオーバー エンジニアリングである可能性があります。オブジェクトを「手動で」削除するだけで十分な場合は、それを検討してください。

于 2013-11-01T20:50:57.870 に答える
1

これは、共有ポインターの優れた使用例のようです。スマート ポインターの背後にある基本的な考え方は、参照をカウントする通常のポインターのように動作するということです。それへの参照を保持するものが他にない場合、それ自体が自動的に解放されます。

あなたの例でそれらを使用する方法は次のようになります

std::vector<std::shared_ptr<Mat> > images;
std::shared_ptr<Mat> mat_ptr (new Mat(height, width, CV_8UC3));
images.push_back(mat_ptr);

共有ポインタの詳細については、こちらの便利なチュートリアルをご覧ください。あなたの質問/問題について何か誤解していた場合は、お気軽に以下をフォローアップしてください。

于 2013-11-01T20:46:39.220 に答える