Gestionnaire de la mémoire

Le gestionnaire de la mémoire (memory manager) conserve une trace des instances créés via la Plateforme. Si ces instances sont toujours présentes à la fin de l’exécution du logiciel, le gestionnaire se charge de les détruire.

Le gestionnaire de la mémoire apporte plusieurs avantages :

  • Simplicité – Le gestionnaire permet de faire abstraction de la destruction des instances créés. Les utilisateurs de la Plateforme, qu’importe leur expérience dans le développement logiciel, n’auront pas à ce soucier de cet aspect technique.
  • Efficacité – La reconstruction 3D requière de base beaucoup de mémoire. Aussi, les informations se propagent d’étapes à étapes. Par souci d’efficacité, il fut décidé que ces données seraient passées par référence (pointeurs), plutôt qu’être dupliquées. Cependant, ce choix rend la destruction des instances partagées plus délicate, d’où la création d’un gestionnaire pour s’en charger.
  • Qualité logiciel – Toutes données non détruite à la fin de l’exécution d’un programme demeure en mémoire jusqu’au redémarrage. Ce problème est connu sous le nom de fuite de mémoire. Le gestionnaire prévient ce genre de problème.

Malheureusement, le gestionnaire de la mémoire apporte aussi son lot d’inconvénient.

  • Concurrence – Dans son implémentation actuelle, le gestionnaire de mémoire ne supporte pas la programmation concurrente (multithreading).
  • Spécifique à la Plateforme – Le gestionnaire ne prend en charge que les instances compatibles à la Plateforme. Plus précisément,  les instances supportées doivent hériter d’une interface offerte par la Plateforme. Cela exclus tous types de données provenant de librairie externes.

Fonctionnement

Le gestionnaire de la mémoire est ramasse-miette à comptage de références (Garbage collector with reference counting).

Utilisation

Il existe différentes manières d’utiliser le gestionnaire de la mémoire :

  1. Utiliser les implémentations existantes. La gestion de la mémoire y sont déjà inclus.
  2. Créer ses propres implémentations grâces aux utilitaires d’implémentations
  3. Parler directement au gestionnaire de la mémoire. Cet approche est déconseillée.

Utilisation des implémentations existantes

Les implémentations existantes peuvent être créé de plusieurs manières selon le contexte.

Si l’implémentation est interne au projet, une instance peut être créé via la méthode Create :

IPosition2D* position = DefaultPosition2D::Create();

Si l’implémentation est externe au projet, une instance peut être créé via une fonction constructrice :
IPosition2D* position = ::CreateDefaultPosition2D();

Si l’implémentation est externe au projet et n’est accessible qu’à l’exécution (Plugins), une instance peut être créé via une fabrique (Factory) :
IPosition2D* position = Position2DFactory::Create(« MyPosition2D »);

Développement de ses propres implémentations

Les utilitaires d’implémentation facilitent le développement d’implémentation géré par le gestionnaire de la mémoire. Chaque constructeur et destructeurs doivent être implémentés via les utilitaires d’implémentations.

Les utilitaires pour les fichiers d’en-têtes (*.h) sont :

CONSTRUCTOR_H(<nom de l'interface parent>, <nom de la classe>);
CONSTRUCTOR_H(<nom de l'interface parent>, <nom de la classe>, <paramètres>);
DESTRUCTOR_H(<nom de la classe>);

Les utilitaires pour les fichiers sources (*.cpp) sont :
DEFAULT_CONSTRUCTOR(<nom de l'interface parent>, <nom de la classe>)
CONSTRUCTOR(<nom de l'interface parent>, <nom de la classe>, <paramètres>)

Exemple

Fichier d’en-tête (MyPosition.h) :


class MyPosition2D : IPosition2D
{
CONSTRUCTOR_H(IPosition2D, MyPosition2D);
CONSTRUCTOR_H(IPosition2D, MyPosition2D, int x, int y);
DESTRUCTOR_H(MyPosition2D);
}

Fichier source (MyPosition.cpp) :

DEFAULT_CONSTRUCTOR(IPosition2D, MyPosition2D) : x(0), y(0) {}
CONSTRUCTOR(IPosition2D, MyPosition2D, (int) x, (int) y)
{
this->x = x;
this->y = y;
}
DESTRUCTOR(MyPosition2D) {}
…