Vermeiden von memory leaks bei der Lagerung von OpenCV Mat-Objekte in STL-Containern
Ich bin mit OpenCV und ich wollen speichern Sie eine Anzahl von Bildern (Mat
Objekte) in einem Vektor. Ich habe erklärt der Vektor wie folgt zu speichern Zeiger auf Mat
Objekte.
std::vector<Mat*> images;
Den Mat
Objekte erzeugt werden, indem die new
Schlüsselwort, und dann Hinzugefügt, um den Vektor.
Mat *img = new Mat(height, width, CV_8UC3);
//set the values for the pixels here
images.push_back(img);
Wie würde ich sicherstellen, dass ich den Speicher frei, indem die besetzten Mat
Objekte um Speicherverluste zu vermeiden?
Was ich gerade mache ist Folgendes:
Mat *im = images.at(index);
//process and display image here
delete(im);
Valgrind ist reporing eine mögliche memory leak mit Referenz auf den erzeugten Mat-Objekte. Bin ich etwas fehlt?
Edit:
Ok. Anscheinend ist es besser zu vermeiden, mit Mat
Zeiger und dynamische Zuweisung Mat
mit new
. Ich habe meine modifizierten code zu verwenden std::vector<Mat>
statt. Ich sehe aber noch einige Blöcke, die zugeteilt wurden, die von Mat
möglicherweise verloren in der Valgrind-Bericht. Ich merke auch, dass die Speicherauslastung steigt stetig, während das Programm ausgeführt wird.
Lassen Sie mich klarstellen, was ich Tue. Ich erschaffe Bilder, die in einer Funktion und legt Sie in einem Zwischenspeicher (intern mit std::deque
). Dieser Puffer wird dann zugegriffen, indem eine andere Funktion zum abrufen und Bild, und übergeben Sie es an eine andere Funktion, die führt die Bearbeitung und das rendering.
class Render {
public:
void setImage(Mat& img) {
this->image = img;
}
void render() {
//process image and render here
}
private:
Mat image;
}
Thread, der kontinuierlich holt Bilder aus dem Puffer und stellt Sie dar.
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();
}
}
Nun, alles, was übergeben wird, die als Objekt-Referenzen (D. H. Mat&
). Ich gehe davon aus, dass nach dem abrufen eines Bildes aus dem Puffer und an die render-Funktion, die nur die Referenz zu diesem Objekt wird in dieser Funktion. Deshalb, wenn ich ein weiteres Bild, es wird nicht länger eine Referenz auf das Objekt, und es wird zerstört werden. Aber Valgrind gibt mir die folgende:
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
...
Und hier ist generateImage()
:
void generateImage() {
Mat img(h, w, CV_8UC3);
//set values of pixels here
this->buffer->pushBack(img);
}
- Der Mat-Klasse verwaltet die Zuweisung von Speicher und hat die Referenz-Zählung, so dass
std::vector<Mat>
erledigt die Arbeit für Sie nur noch und kopiert den Zeiger plus size Informationen ohne unnötige Zuweisungen und Kopien der großen Matrix-Inhalten. - Ich habe aktualisiert die Frage, wobei einige Teile des Codes nach dem Update es, wie Sie vorgeschlagen. Ich noch Begegnung ein Speicher-Leck, obwohl das problem noch besteht.
- Die Teile von deinem code hier funktionieren sollte. Können Sie erläutern, wie ein bit auf, das undurchsichtige Zeiger? Wo kommt es her, wie wird es initialisiert, und wer besitzt es und ruft den Destruktor der
ImageProcessor
wenn es nicht mehr benötigt wird? Beachten Sie, dassvoid * opaque=new ImageProcessor; do_stuff(opaque); free opaque;
ruft den Konstruktor derImageProcessor
aber der Destruktor vonvoid
). - Die transparenten Zeiger ist im Grunde ein Zeiger auf eine
ImageProcessor
Objekt. Wie ich bereits erwähntprocess()
ist eine thread-Funktion. Ich erstelle ein thread mit dem Pthread - Bibliothek und übergeben Sie einen Zeiger aufprocess()
und einen Zeiger auf ein Objekt, das ist im Grunde die parameter der thread-Funktion. Dies ist, wie die threads erstellt werden, mitpthread_create()
. Hier, ich bin nur auf der Durchreise einen Verweis aufImageProcessor
so dass der thread die Methoden aufrufen. Wann und wo der DestruktorImageProcessor
aufgerufen wird, sollte das kein problem sein. Da bin ich auf das entfernen derMat
Objekte aus dem Puffer.
Du musst angemeldet sein, um einen Kommentar abzugeben.
Scheint dies ein großer Fall für shared Pointer. Die grundlegende Idee hinter einem smart-pointer ist, dass es verhält sich wie eine Referenz gezählt regelmäßige Zeiger. Wenn nichts anderes, hält eine Referenz auf diese, wird es automatisch gratis-s selbst.
Die Weise, die Sie möchten, verwenden Sie in Ihrem Beispiel wäre
Hier's eine praktische Anleitung für mehr über shared Pointer. Wenn ich da etwas falsch verstanden zu Ihrer Frage/problem, fühlen Sie sich frei, um follow-up unten.
Wenn Sie vorsichtig sind, um tatsächlich löschen Sie die Objekte, dann gibt es keine Speicherverluste. That being said, es gibt Möglichkeiten zum speichern von Zeigern in Vektoren, sind weniger anfällig für menschliche Fehler (D. H. Sie vergessen, um die Objekte gelöscht, die in irgendeiner Ecke bei der Anwendung).
Wenn Sie mit C++11 ist, dann würde ich empfehlen
std::shared_ptr
anstelle von raw-Pointern. Dadurch wird sichergestellt, dass der Speicher gelöscht wird (automatisch) wenn es nicht mehr ist code, der verwendet IhreMat
Objekt.Gibt es auch den Vorteil, dass neben ändern und den Typ des Zeigers gibt es nicht andere änderungen, die Sie zu tun haben. Die üblichen
ptr->member
und*ptr
Ausdrücke sind gültig fürstd::shared_ptr
als gut.Hier einige Dokumentation auf
std::shared_ptr
. Auch, je nachdem Sie bestimmte Bedürfnisse, möchten Sie vielleicht zu schauen instd::reference_wrapper
als gut.Edit: Seit C++11 ist nicht eine option, die Sie könnten versuchen,
boost::shared_ptr
— standardstd::shared_ptr
basiert auf der Boost one. Wenn der Boost ist nicht eine option, entweder, Sie könnten setzen Sie Ihre eigene shared-pointer, es ist nicht sehr schwer.Die Größe des Programms etwas anderes zu denken. Wenn Ihre Anwendung ist ziemlich klein und es gibt kaum eine chance für Sie, zu vergessen, einige Ecke Fall, dass verursachen könnte, memory-leaks, all das könnte sein, over-engineering. Im Fall, einfach das löschen der Objekte "von hand" tun, dann erwägen, dies zu tun.
Mat
Objekt, das erstellt wurde mit dernew
keyword? Ich weiß, dass Sie ein Objekt erstellen, ohnenew
sollte alle Ressourcen freigeben, wenn Sie nicht vorhanden sind, verweist. Aber ich bin mir nicht sicher über die dynamische Erstellung von es mitnew
.new
müssen Sie zerstören es (irgendwann) mitdelete
. Siehe mein edit über das, was zu prüfen, wie alternativen zu C++11.