Bonjour,
J'ai effectué une optimisation de la vitesse de calcul d'une opération en optimisant la mémoire cache et je me pose des questions sur la libération de la mémoire cache pour éviter des fuites mémoires.
J'ai une liste d'objet de types différents qui héritent d'une classe commune. En temps normal, j'utiliserais une liste de pointeur vers cette classe commune et je ferrais un simple parcours de la liste. Cela signifie que l'on a une liste d'adresse mémoire, cette liste d'adresse est elle même allouée à un emplacement particulier.
En terme de gestion de la mémoire, cela signifie que le programme va faire un accès à adresse mémoire de la liste, ce qui enclenche un chargement dans la mémoire cache d'une portion de la RAM qui contient cette liste d'adresse. Ensuite lorsque l'on accede à un élément de la liste, on va charger dans la mémoire cache la portion qui concerne cet objet. Enfin, une fois l'objet traité, on accède de nouveau à la liste en chargeant de nouveau la mémoire cache. Ainsi à chaque changement de portion de mémoire, on perd du temps. Sans compter que le traitement d'un objet peut dépendre d'un objet voisin ce qui demande d'autres mise à jour de la mémoire cache.
La solution que j'ai implémenté consiste à utiliser une liste chaînée dont les objets sont placés de manière consécutive dans la mémoire, ainsi les chargements de la mémoire cache deviennent plus rare.
tout d'abord, ai-je réinventé la roue et existe t'il un type standard de liste permettant d'effectuer la même opération?
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32 // exemple de trois objets de type différents qui héritent de ClassP // 1) taille de chaque type de classe uint sizeA = sizeof(ClassA); uint sizeB = sizeof(ClassB); uint sizeC = sizeof(ClassC); // 2) allocation de l'espace mémoire et calcul des adresses des futurs objets void* address = malloc(sizeA+sizeB+sizeC); void* addressA = address; void* addressB = addressA+sizeA; // l'addition n'étant pas valable pour le void* en réalité je passe par un cast vers char*, je n'écris pas ces opérations par soucis de lisibilité void* addressC = addressB+sizeB; // 3) creation des objets aux addresses définies ClassA* a = new(addressA) ClassA(); // a == addressA == address ClassB* b = new(addressB) ClassB(); // b == addressB ClassC* c = new(addressC) ClassC(); // c == addressC // 4) paramétrage des objets a->next = b; b->next = c; c->next = nullptr; // 5) traitement ClassP *current = a; do { a->exec(); current = current->next; } while(current != nullptr) // 6) liberation de l'espace mémoire delete a; delete b, delete c; free(address);
ensuite, ce qui me gène est la libération de l'espace mémoire:
je fais appel à 'delete a' pour accéder au destructeur avant de désallouer, mais dans les faits je désalloue deux fois la même adresse mémoire (ce qui ne fonctionne pas).
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3 delete a; // a == address free(address);
j'imagine que lors de l'allocation, il existe une liste dans le système de gestion du programme qui fait le lien entre les addresses et la taille des objets alloués. De cette manière si j'alloue l'emplacement pour un objet le programme est capable d’empêcher une allocation sur cet espace mémoire et de désallouer la bonne taille.
Dans mon exemple plus haut, j'effectue une sorte de double allocation et je désalloue deux fois.
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7 char* c = (char*) malloc(15); free(c) // on n'indique pas la taille à la libération, cela signifie que le programme connait la taille de l'allocation d'une autre manière ClassP* p = new ClassA(); delete(p) // on a perdu l'information de la classe d'origine: sizeof(ClassA) != sizeof(classP), // donc le programme connait la taille de l'allocation sans avoir besoin de connaitre le type
- Est ce que `delete a` seul ne désalloue pas en même temps le pointeur address?
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5 void* address = malloc(size) ClassA* a = new(address) ClassA(); delete a; free(address);
- Est ce que `free(address)` est il suffisant pour désallouer en même temps `a`, `b` et `c`? quid du destructeur?
merci d'avance
Partager