Finden Sie Speicherlecks in C++

Saad Aslam 16 Februar 2024
  1. Speicherlecks in C++
  2. Behandeln Sie Speicherlecks in C++
  3. Möglichkeiten zur Vermeidung von Speicherlecks in C++
  4. Verwenden Sie Valgrind, um Speicherlecks in C++ zu finden
  5. Verwenden Sie die CRT-Bibliothek, um Speicherlecks in C++ zu finden
Finden Sie Speicherlecks in C++

Dieser Artikel erklärt Speicherlecks, ihre Ursachen, wie man sie identifiziert und wie man sie mit der Programmiersprache C++ verhindert.

Speicherlecks in C++

Speicher wird als “Leak” bezeichnet, wenn der Teil des Speichers, den der Programmierer zuvor einem Zweck zugewiesen hat, für einen anderen verwendet wird. Wenn so etwas passiert, hebt der Programmierer die Ressource nicht korrekt auf.

An diesem Punkt benötigt das Programm keinen solchen Arbeitsspeicher. Infolgedessen gibt es keinen Grund, die Reservierung für diesen Sitzplatz aufrechtzuerhalten.

Speicherlecks treten in C++ auf, wenn Programmierer Speicher mit dem Schlüsselwort new zuweisen, aber den Speicher nicht mit der Funktion delete() oder dem Operator delete[] freigeben; dies führt zu Gedächtnisverlust. Memory Leakage wird meistens durch den falschen delete-Operator verursacht.

Der Operator delete[] kann Daten in einem Array freigeben.

Wenn wir das Öl in unserem Auto wechseln, aber gleichzeitig eine Dichtung vernachlässigen oder eine Schraube festziehen, werden wir wahrscheinlich auf erhebliche Probleme beim Fahren stoßen.

Der Motor unseres Autos wird schließlich festsitzen, da das gesamte Öl schließlich aus dem Auto fließen wird; Die C++-Programmierung führt zu genau demselben Ergebnis.

Wenn ein Programmierer Speicher dynamisch zuweist, aber diesen Speicher anschließend nicht freigibt, entsteht ein Speicherleck, und die Speicherzuweisung kann wie folgt durchgeführt werden.

int *data;
data = (int *)malloc(8);
char *login = new char(40);

Wenn wir Speicher dynamisch zuweisen, stammt dieser Speicher aus dem Heap, der ein Teil des Systemspeichers ist, den C++ verwendet. Der Stack ist der Ort, an dem Variablen und Funktionen entnommen werden.

Es wird ein Speicherleck geben, wenn wir nicht den folgenden Code hinzufügen, um diese Zuordnungen zu löschen. Diese Lecks würden sich im Laufe der Zeit aufbauen und je nach unserer Programmlogik dazu führen, dass unsere Anwendung fehlschlägt.

free(data);
delete login;

Hier ist ein weiterer Fall, in dem eine Funktion erstellt wird, um acht Bytes Heap-Speicherplatz für einen Zeiger zuzuweisen. Dies belegt auf einem 64-Bit-Computer 8 Bytes.

Diese Bytes werden nicht freigegeben, nachdem das Programm die Ausführung abgeschlossen hat.

#include <iostream>
using namespace std;

void data_leak() { double *pointer = new double(28.54); }
int main() { data_leak(); }

Das Hinzufügen des folgenden Schleifencodes im obigen Codeblock bewirkt, dass eine Million Bytes zugewiesen, aber nie freigegeben werden. Wir sollten wahrscheinlich alle geöffneten Dateien speichern, bevor wir diesen Code ausführen.

Selbst die modernsten Betriebssysteme hätten damit keine Probleme, aber wenn wir der for-Schleife eine zusätzliche Anweisung hinzufügen würden, könnten wir in Schwierigkeiten geraten. Aus diesem Grund können Speicherlecks so gefährlich sein.

for (int j = 0; j < 150000; j++) {
  data_leak();
}

Behandeln Sie Speicherlecks in C++

Zuerst erstellen wir eine Funktion namens func_to_handle_memory_leak(),, dann deklarieren wir einen Zeiger vom Typ Integer, um ein Speicherleck zu behandeln, und weisen dann einen ganzzahligen Wert mit dem Schlüsselwort new int() zu.

void func_to_handle_memory_leak() { int* ptr = new int(6); }

Jetzt verwenden wir die Funktion delete(), um den vorherigen Speicher zu löschen und Speicherlecks im Programm zu vermeiden. Alle Aktivitäten werden ausgeführt, sobald die Funktion aufgerufen wird, und zugewiesener Speicher wird freigegeben, bevor die Funktion zurückkehrt.

delete (ptr);

In der main-Funktion rufen wir unsere func_to_handle_memory_leak()-Funktion auf.

int main() {
  func_to_handle_memory_leak();
  return 0;
}

Vollständiger Quellcode:

#include <iostream>
using namespace std;

void func_to_handle_memory_leak() {
  int* ptr = new int(6);
  delete (ptr);
}
int main() {
  func_to_handle_memory_leak();
  return 0;
}

Möglichkeiten zur Vermeidung von Speicherlecks in C++

  1. Anstatt den Speicher manuell zu verwalten, sollten Sie sich bemühen, wann immer möglich, intelligente Zeiger zu verwenden.
  2. Anstelle von char\* sollten Sie std::string verwenden. Die Klasse std::string ist blitzschnell und hochoptimiert; Es kümmert sich intern um die gesamte Speicherverwaltung.
  3. Der beste Weg, Speicherlecks in C++ zu vermeiden, sind ein paar new- und delete-Aufrufe auf Programmebene. Alles, was dynamischen Speicher erfordert, sollte in einem RAII-Objekt vergraben werden, das den Speicher freigibt, wenn es den Gültigkeitsbereich verlässt; RAII weist Speicher im Konstruktor zu und gibt ihn im Destruktor frei, sodass die Speicherzuweisung garantiert aufgehoben wird, wenn die Variable den aktuellen Gültigkeitsbereich verlässt.
  4. Speicher sollte mit dem Schlüsselwort new zugewiesen werden, und Speicher sollte mit dem Schlüsselwort delete freigegeben werden, wobei der gesamte Code zwischen diesen beiden Anweisungen geschrieben wird.

Verwenden Sie Valgrind, um Speicherlecks in C++ zu finden

Ein Speicherleck ist eine der heimtückischsten Arten von Programmierfehlern, da es sich nicht als auffälliges Problem manifestiert, bis Sie den Speicher Ihres Systems erschöpft haben und ein Aufruf von malloc fehlschlägt.

Ohne Garbage Collection kann etwa die Hälfte Ihrer Bemühungen darauf verwendet werden, sicherzustellen, dass der Speicher ordnungsgemäß freigegeben wird, wenn Sie mit Sprachen wie C oder C++ arbeiten.

Um die aktuelle Liste der unterstützten Tools anzuzeigen, führen Sie einfach Valgrind aus und wählen Sie dann das Tool aus, das Sie beim Ausführen Ihres Codes verwenden möchten.

Wenn wir Valgrind mit dem Tool memcheck ausführen, können wir den genauen Speicherverbrauch überprüfen. es liefert eine Zusammenfassung aller free- und malloc-Anrufe.

Zur Erklärung verwenden wir ein einfaches Programm namens memoryleakdemo.

#include <stdlib.h>

int main() {
  char *x = new char[100];
  return 0;
}

Dadurch werden einige Informationen über das Programm angezeigt, einschließlich einer Liste von malloc-Aufrufen ohne entsprechende kostenlose Anrufe.

% valgrind --tool=memcheck --leak-check=yes memoryleakdemo

Wir wissen, dass ein Aufruf von malloc in main für das Speicherleck verantwortlich war, aber wir können die genaue Zeilennummer nicht lokalisieren. Das Problem ist, dass wir das Programm nicht mit der GCC-Option -g erstellt haben, die Debugging-Symbole bereitstellt.

Die folgende Ausgabe erhalten wir, wenn wir das Programm mit Debugging-Symbolen neu kompilieren.

==2022== 100 bytes in 1 blocks are definitely lost in loss record 1 of 1
==2022==    at 0x1B900DD0: malloc (vg_replace_malloc.c:131)
==2022==    by 0x804840F: main (memoryleakdemo.c:5)

Verwenden Sie die CRT-Bibliothek, um Speicherlecks in C++ zu finden

Speicherlecks können mit dem Visual Studio-Debugger und den C-Laufzeitbibliotheken (CRT) lokalisiert und identifiziert werden.

Aktivieren Sie die Speicherleckerkennung

Sie müssen die folgenden Anweisungen in Ihre Anwendung aufnehmen, um die Debug-Heap-Funktionen zu aktivieren.

#define _CRTDBG_MAP_ALLOC
#include <crtdbg.h>
#include <stdlib.h>

Nachdem Sie diese Befehle verwendet haben, um die Debug-Heap-Funktionen zu aktivieren, können Sie einen Aufruf von _CrtDumpMemoryLeaks vor einem Anwendungsausgangspunkt einfügen, damit ein Speicherleckbericht angezeigt wird, wenn Ihr Programm beendet wird.

_CrtDumpMemoryLeaks();

Der Speicherleckbericht wird an die Registerkarte Debug des Fensters Output gesendet, wenn _CrtDumpMemoryLeaks ausgeführt wird. Dies ist das Standardverhalten.

Sie können die Funktion _CrtSetReportMode verwenden, um den Bericht an einen anderen Ort zu senden.

Die Ausgabe des CRT Library Memory Leak:

_CrtDumpMemoryLeaks erstellt einen Speicherleckbericht ähnlich dem unten gezeigten, wenn Ihre Anwendung _CRTDBG MAP ALLOC nicht deklariert.

Detected memory leaks!
Dumping objects ->
{18} normal block at 0x00780E80, 64 bytes long.
 Data: < > CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD
Object dump complete.

Der Speicherleckbericht sieht so aus, wenn Ihre Anwendung _CRTDBG MAP ALLOC angibt.

Detected memory leaks!
Dumping objects ->
c:\users\username\documents\projects\leaktest\leaktest.cpp(20) : {18}
 normal block at 0x00780E80, 64 bytes long.
 Data: < > CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD
Object dump complete.
Autor: Saad Aslam
Saad Aslam avatar Saad Aslam avatar

I'm a Flutter application developer with 1 year of professional experience in the field. I've created applications for both, android and iOS using AWS and Firebase, as the backend. I've written articles relating to the theoretical and problem-solving aspects of C, C++, and C#. I'm currently enrolled in an undergraduate program for Information Technology.

LinkedIn

Verwandter Artikel - C++ Memory