Comment détecter les fuites de mémoire en C/C++ avec Valgrind

Comment Detecter Les Fuites De Memoire En C C Avec Valgrind



Valgrind est un outil largement utilisé pour déboguer et profiler les logiciels principalement écrits en C, C++ et d'autres langages. Il aide les développeurs à détecter les fuites de mémoire, à traquer les erreurs d'accès à la mémoire et à profiler l'exécution de leurs programmes.

Lorsque vous exécutez un programme sous Valgrind, celui-ci instrumente dynamiquement l'exécutable du programme, lui permettant de surveiller l'utilisation de la mémoire et le comportement d'exécution du programme.

Fuites de mémoire en C++

Il est important de noter que Valgrind est principalement conçu pour les programmes C et C++ et peut ne pas fonctionner aussi efficacement avec d'autres langages ou dans tous les scénarios. De plus, exécuter un programme sous Valgrind peut ralentir considérablement son exécution, c'est pourquoi il est souvent utilisé pendant le développement et le débogage plutôt que dans les environnements de production.







Lorsqu'une mémoire créée dynamiquement n'est pas correctement libérée, cela peut provoquer des fuites de mémoire en C/C++ qui épuiseront lentement les ressources mémoire disponibles. Cela peut entraîner une consommation excessive de mémoire et une dégradation des performances du programme.



Installation Valgrid

Pour installer Valgrind sur un système Linux, ouvrez un terminal et mettez à jour vos référentiels de packages à l'aide du gestionnaire de packages spécifique à votre distribution Linux. La commande suivante fonctionne pour les systèmes basés sur Ubuntu et Debian :



$ sudo mise à jour appropriée

Utilisez le gestionnaire de packages pour installer Valgrind. Encore une fois, la commande peut varier en fonction de votre distribution Linux. Utilisez la commande suivante pour les systèmes basés sur Ubuntu et Debian :





$ sudo apte installer porte électorale

Lorsque vous y êtes invité, entrez votre mot de passe utilisateur et appuyez sur « Entrée ». Notez que votre compte utilisateur nécessite des privilèges administratifs pour installer le logiciel. Le gestionnaire de packages télécharge et installe Valgrind avec toutes les dépendances nécessaires. Le processus peut prendre quelques minutes.



Une fois le processus d'installation terminé, vous pouvez confirmer l'installation réussie de Valgrind en exécutant la commande suivante comme étape de vérification :

$ porte électorale --version

Cette commande affiche les informations de version de Valgrind si elle est installée avec succès.

C'est ça! Valgrind devrait maintenant être installé sur votre système Linux et vous pouvez l'utiliser pour analyser et déboguer vos programmes C/C++ pour détecter les fuites de mémoire et d'autres problèmes.

Créer un fichier dans Ubuntu

Pour commencer à travailler sur le programme, nous devons d'abord créer un fichier dans Ubuntu. Pour la création de fichiers, nous utilisons l'éditeur de texte nano. Nous écrivons donc la commande sur le terminal comme suit :

$ nano fichier1

Ici, nano est le nom de l'éditeur de texte en cours d'exécution. L'argument « file1 » représente le nom du fichier que vous avez l'intention d'ouvrir ou de créer à l'aide de l'éditeur de texte nano. Nano ouvre le fichier pour le modifier s'il existe déjà ; sinon, il génère un nouveau fichier avec le nom fourni. Comme nous n'avons pas un tel fichier, il crée un nouveau document portant le nom « fichier1 ».

Une fois la commande exécutée, l'éditeur nano s'ouvrira, vous fournissant un canevas vierge pour saisir ou modifier le contenu du fichier « file1 ». Vous pouvez commencer à saisir ou à coller le contenu existant dans l'éditeur.

Maintenant que tous les prérequis sont remplis, nous créons quelques exemples pour utiliser Valgrind afin de détecter les fuites de mémoire dans les programmes C++.

Exemple 1:

Le premier exemple que nous fournissons montre un exemple simple d'allocation dynamique de mémoire à l'aide de la fonction « malloc » de la bibliothèque en C.

#include

int principal ( )

{

carboniser * un = malloc ( 102 ) ;

retour 0 ;

}

Voici une ventilation du code :

Nous incluons d'abord le fichier d'en-tête de bibliothèque standard qui fournit des fonctions telles que malloc pour l'allocation et la désallocation dynamiques de mémoire.

La ligne int main() déclare la fonction principale. Ensuite, le char *a = malloc(102); déclare une variable pointeur « a » de type char* (pointeur vers char). Il utilise la fonction « malloc » pour allouer dynamiquement la mémoire à un tableau de 102 éléments char (102 octets au total). La taille de l'allocation mémoire, exprimée en octets, est envoyée en entrée à la fonction malloc et génère un pointeur vers le bloc mémoire fraîchement créé. Le pointeur char* « a » se voit attribuer cette valeur de pointeur. Enfin, le « retour 0 ; » signifie la fin de la fonction principale.

En bref, ce code alloue dynamiquement la mémoire pour un tableau de 102 éléments char en utilisant « malloc » et attribue l'adresse mémoire au pointeur « a ». Cependant, notez que le code n'utilise ni ne manipule la mémoire allouée de quelque manière que ce soit et n'inclut pas la désallocation de la mémoire en utilisant free.

Lorsque nous exécutons ce programme via Valgrind avec l'option « –leak-check=full », il effectue une vérification des fuites de mémoire et fournit un rapport de sortie.

Le rapport de sortie produit par Valgrid est le suivant :

Exemple 2 :

Pour commencer cette illustration, nous créons d'abord un fichier « test2 » à l'aide de l'éditeur de texte nano comme expliqué précédemment en écrivant la commande :

$ nano test2

Maintenant, nous écrivons un programme C++ pour vérifier s'il y a une fuite de mémoire en utilisant Valgrind :

#include

#include

#include

const int a_s = 3000 ;

int main ( ) {

int * ia = malloc ( taille de ( int ) * comme ) ;

pour ( int je = 0 ; je < comme; je++ ) {

il [ je ] = je;

}

sable ( temps ( NUL ) ) ;

int rn = rand ( ) % comme;

imprimer ( 'il[%d] : %d \n ' , rn, ça [ rn ] ) ;

retour 0 ;

}

Passons en revue le programme.

Le code inclut les fichiers d'en-tête nécessaires et définit la variable constante « a_s » avec une valeur de 3000. Dans la fonction main(), un pointeur « ia » de type int* est déclaré et la mémoire est allouée dynamiquement à l'aide du « malloc » fonction. L'expression « sizeof(int) * a_s » détermine la mémoire totale requise pour stocker le nombre « a_s » d'entiers. Tous les éléments du tableau « ia » sont initialisés par la boucle « for » avec sa valeur d'index correspondante. Par exemple, ia[0] sera 0, ia[1] sera 1, et ainsi de suite.

Le générateur de nombres aléatoires est généré à l'aide de la fonction « srand » en utilisant l'heure actuelle. Cela garantit que le programme produit un ensemble unique d'entiers aléatoires à chaque fois qu'il est exécuté. La fonction « rand » génère un nombre aléatoire et « rn » se voit attribuer le résultat de rand() % a_s. L'opérateur de module « % » limite la plage du nombre aléatoire entre 0 et a_s – 1, ce qui correspond à un index valide dans le tableau « ia ».

Enfin, le programme utilise la fonction « printf » pour imprimer la valeur à l'index « rn » sélectionné au hasard du tableau « ia », ainsi que l'index correspondant.

Lorsque vous exécutez ce programme via Valgrind, il génère le rapport de sortie suivant :

  Une capture d'écran d'un programme informatique Description générée automatiquement

Conclusion

Nous avons découvert l'utilisation de l'outil Valgrind pour détecter les fuites mémoire dans un programme C++. Le guide d'installation du Valgrind est fourni dans un premier temps. Après cela, nous avons développé la création d'un fichier dans Ubuntu à l'aide de l'éditeur de texte nano. Au final, en utilisant ces prérequis, nous avons exécuté deux exemples C++ pour vérifier les fuites de mémoire. Le rapport généré par Valgrind est également joint et montre les fuites de mémoire dans le fichier fourni.