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.

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);
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?

ensuite, ce qui me gène est la libération de l'espace mémoire:

Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
 
delete a; // a == address
free(address);
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).

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.

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
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
 
void* address = malloc(size)
ClassA* a = new(address) ClassA();
delete a;
free(address);
- Est ce que `delete a` seul ne désalloue pas en même temps le pointeur 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