SOCIÉTÉ

BLOGS

J'ai la mémoire qui flanche : 1, 2, 3 soleil !

25.01.2012
par Olivier Deschanels
Ram

Après avoir examiné les tables des variables process et inter-process dans le billet précédent, nous continuons notre exploration de la mémoire en étudiant la mémoire cache.

La mémoire cache est dédiée aux données. Nous trouverons donc dans cette zone mémoire les enregistrements, les index et tout ce qui est nécessaire pour leur gestion : sélections courantes, tables d'allocations, tables d'adresses ...

 

Lorsqu'une base est ouverte par un moteur 4D, les paramètres de la mémoire cache sont lus et le moteur tente d'allouer la mémoire demandée. Mais avant d'aller plus loin, revenons au point départ et plus exactement au paramètrage de la base.

 

Allocation de la mémoire cache

La mémoire cache est allouée dès le démarrage de la base, et cela une fois pour toute. Elle ne pourra plus grossir ni se réduire par la suite. Il est donc primordial de bien la dimensionner. Malheureusement il n'existe pas de recette miracle permettant à coup sûr de donner la bonne taille au cache, cela serait trop simple ! Nous allons étudier dans la suite de cet article le fonctionnement du cache et vous donner quelques éléments de réflexion et d'analyse.

La première chose à régler est l'utilisation ou non du cache adaptatif. Dans les propriétés de la base, dans la page "Base de données", onglet "Mémoire" vous avez la possibilité de choisir le calcul adaptatif du cache via une case à cocher.
Si vous travaillez sur une application que vous utilisez vous-même en production et sur une machine dont vous avez la parfaite connaissance, vous n'avez alors aucune raison d'utiliser le calcul adaptatif. Si, au contraire, vous éditez un logiciel qui est installé directement par vos clients sur des machines que vous ne connaissez pas, alors le calcul adaptatif est là pour vous !
Si donc vous maîtrisez l'environnement de déploiement de votre base, décochez le calcul adaptatif pour obtenir l'écran suivant :

 

 

La taille désirée est alors demandée directement. Vous avez la liberté de fixer la valeur que vous jugez nécessaire pour votre base. Bien entendu il faut que cela soit compatible avec la mémoire physique et les autres utilisations de la mémoire (OS, 4D, autres applications...). Au lancement 4D tentera d'allouer cette zone en mémoire. S'il n'y arrive pas il réduira la taille du cache jusqu'à parvenir au lancement de la base.
Si vous fixez une taille trop grande, celle-ci risque de ne pas être respectée par 4D. Si vous fixez une taille trop petite, la base ne fonctionnera pas de façon optimale. L'équilibre se déduit grâce à une bonne connaissance des données de la base, du code qui les manipule et de l'expérience.

Si vous éditez vos créations logicielles avec 4D, alors vous avez besoin du calcul adaptatif en cochant la case dédiée :


 

Dans ce cas vous avez différents réglages permettant en premier lieu de fixer la partie de la mémoire vive que vous ne voulez pas toucher pour la réserver aux autres applications et au système d'exploitation. Dans la zone mémoire restante ainsi définie vous pouvez alors décider du pourcentage que vous allouez au cache de 4D. Dans l'image ci-dessus c'est la moitié. Ensuite vous pouvez contraindre le résultat à rester dans une fourchette de valeur en définissant les bornes minimale et maximale.

Dans les deux cas (que le calcul soit adaptatif ou non), 4D essaiera d'allouer la mémoire demandée. S'il n'y arrive pas, alors il essaiera à nouveau en divisant par deux la valeur demandée, et ainsi de suite. La valeur du cache sera toujours au minimum de 100 méga-octets faute de quoi 4D ne peut se lancer.
Sur une version 32 bits du moteur 4D, la mémoire que vous pouvez réserver pour le cache est au maximum de 2,3 giga-octets. Sur une version 64 bits, cette limite n'existe plus ; il est cependant recommandé de ne pas dépasser la valeur de la mémoire physique, même si rien ne l'empêche. Dans ce dernier cas les performances peuvent être fortement dégradées.

Une fois la base lancée, le cache possède sa taille définitive et le choix du calcul adaptatif ou non n'a plus d'influence sur la suite de la vie de l'application.

Une zone, quatre armoires

Comment est constitué le cache mémoire ?

La zone mémoire réservée au cache étant allouée, 4D s'empresse alors de la diviser en 4 parties égales. Chaque partie doit être considérée comme une armoire à données indépendantes. Lorsque les données arrivent du disque dur suite à une requête vers la base de données elles sont stockées dans le cache avant d'être transmises en tant que résultat de la requête. Les données alimentent alors peu à peu la première armoire. Mais cette armoire n'est pas équipée de simples étagères comme les armoires que l'on achète en kit dans un magasin bleu et jaune. Non, notre armoire à données est constituée de multiples tiroirs de différentes tailles, digne des plus grands ébénistes ! Lorsqu'une donnée de 128 octets, par exemple, arrive dans le cache, 4D cherche un tiroir correspondant à la taille 128. Si ce tiroir existe il l'ouvre et ajoute la donnée à l'intérieur. Si le tiroir n'existe pas il va construire un tiroir permettant de stocker un certain nombre d'objets de 128 octets. Supposons qu'ensuite un objet de 64 octets arrive dans le cache. Il utilisera un tiroir dédié aux objets de 64 octets car même s'il y a de la place dans le tiroir des 128 octets celle-ci est réservée pour des objets de 128 et non pour des objets de 64 octets. Quand ce sont des objets de plus grande taille, comme par exemple des sélections courantes importantes, les tiroirs peuvent être dimensionnés pour ne recevoir qu'un seul objet.
Suite à une libération de la place (effacement d'une sélection courante, ou autre) un tiroir peut devenir vide d'objet. A ce moment là seulement, il est possible de réaffecter son utilisation pour lui donner la possibilité de recevoir des objets d'une autre taille.
Lorsque la mémoire allouée pour la première armoire a été entièrement découpée en tiroirs, alors la seconde armoire est mise en oeuvre. Les tiroirs de la première et la deuxième armoire sont actifs et continuent de se remplir et de stocker les données.
La troisième et la quatrième armoire sont ensuite utilisées lorsque le besoin se fait ressentir.

1, 2, 3, Soleil

A présent, il nous faut envisager ce qu'il se passe lorsque la quatrième armoire est pleine et qu'il faut stocker un objet ne rentrant dans aucun des tiroirs déjà créés. Il est temps de faire le ménage. Le principe est très simple et ressemble beaucoup à celui que j'utilise lorsque je ne retrouve plus mes t-shirts préférés (t-shirts au logo de 4D cela va de soi !) dans mon armoire à vêtements. Je prends alors mon courage à deux mains et sort tous les vêtements sur le lit pour réorganiser toute mon armoire. 4D procède pratiquement de la même façon. Lorsque la quatrième armoire arrive à saturation, alors 4D vide entièrement l'armoire. Mais nul besoin de mettre son contenu ailleurs comme mes vêtements que j'étale sur le lit afin de reconstituer des piles, car le cache n'étant qu'une recopie des données stockées sur le disque, les données existent déjà ailleurs. La première armoire à données du cache est donc simplement vidée par effacement pur et simple de son contenu. Bien sûr 4D prend soin de stocker les données non sauvegardées avant de vider l'armoire !
Pourquoi ce choix radical ?
En fait il y aurait une autre solution consistant à maintenir un compteur d'utilisation pour chaque objet ainsi qu'une date de dernière utilisation. Grâce à ces deux données alors nous pourrions sélectionner de manière "intelligente" les objets les moins utilisés depuis le plus longtemps et ainsi travailler au plus juste. L'idée est séduisante, mais le résultat ne le serait pas. En effet les traitements seraient extrêmement nombreux et le temps passé à maintenir les informations nécessaires, ainsi que la place nécessaire à leur stockage en mémoire rendraient le système lent et peu efficace. La méthode radicale consistant à vider un quart du cache d'un coup permet d'optimiser la phase de reconstruction d'une armoire vide. Il y avait certes des données dans l'armoire que l'on vide ainsi, et qu'il aurait été intéressant de conserver dans le cache, mais l'expérience montre qu'il vaut mieux avoir à les recharger qu'à essayer de les conserver à tout prix. Si vous lisez régulièrement mes blogs vous vous doutez que ce genre de solution simple me plaît particulièrement car elle correspond à ce que j'explique sous forme de crédo : faites simple et vous serez efficace !

Retenez donc la comptine enfantine du jeu 1, 2, 3, soleil : au quatrième temps si vous bougez, vous retournez au départ ! A la quatrième armoire pleine, on vide la première pour recommencer, puis la deuxième et ainsi de suite

Ne pas bouger !

A l'instar du jeu 1, 2, 3, soleil, il faut bouger au minimum pour gagner. En effet, si vous arrivez à maîtriser la taille des objets en mémoire cache, alors vous aurez besoin moins souvent de vider une armoire. Si j'arrivais à bien plier mes t-shirts en jolies piles comme dans les magasins, je n'aurais sans doute plus besoin de vider mon armoire sur mon lit !
Si j'ai perdu espoir de savoir plier correctement mes t-shirts (et je ne parle pas des chemises !), j'ai quelques idées pour contrôler la taille des objets en mémoire cache.

Nous avons vu précédemment que ce ne sont pas les grosses sélections qui posent problème car elles utilisent des tiroirs dédiés qui sont ré-attribués très facilement. Non, ce sont les petits objets courants comme par exemple les enregistrements. Encore une fois c'est comme dans mon armoire à vêtements : ma parka d'hiver laisse facilement sa place au printemps lorsqu'elle retourne dans la malle du grenier ; ce sont les t-shirts de tous les jours qui posent problème car il faut y accéder rapidement dans une pile plus ou moins bancale.
Maîtriser la taille des enregistrements commence par en limiter la taille globale. Un enregistrement avec peu de champs aura plus de chance d'être dans une taille similaire à un autre qu'un enregistrement avec de multiples champs plus ou moins utilisés. Même s'il est évident que tous les enregistrements ne peuvent pas avoir la même taille à partir du moment où il y a des champs de taille variable, il ne faut pas pour autant faire en sorte que tous les enregistrements aient des tailles différentes !

L'autre axe de travail pour éviter de faire bouger le cache est très simple. Si vous ne voulez pas le faire bouger, ne lui demandez pas de stocker des données inutiles. Cela rejoint mon blog nommé "l'effet papillon". Si vous construisez une requête en deux recherches distinctes (CHERCHER immédiatement suivi d'un CHERCHER DANS SELECTION) au lieu d'une recherche combinée (CHERCHER avec le paramètre *) alors non seulement vous sollicitez deux fois plus le réseau, mais également le cache. En effet la première recherche produira une sélection courante qu'il faudra stocker dans le cache, et chargera un enregistrement courant qu'il faudra lui aussi charger dans le cache. La seconde recherche fera le même travail au niveau du cache. L'effet papillon a donc perturbé le cache. Mais il y a plus grave. En effet les recherches non combinées peuvent produire des recherches séquentielles au lieu d'une recherche indexée. Dans le cas d'une recherche séquentielle les enregistrements de la table de recherche montent dans le cache, alors que dans le cadre d'une recherche indexée se sont les pages d'index qui montent dans le cache. Dans la très grande majorité des cas, il est préférable de charger dans le cache des pages d'index plutôt que des séries d'enregistrements car les données des pages d'index sont plus compactes et nécessitent donc moins de mémoire. Tout ce qui économisera la mémoire provoquera moins de vidage d'une armoire pour faire de la place et sera donc plus efficace.

Les index peuvent aider, mais le contraire est également vrai. En effet un index n'est bénéfique que s'il est utilisé. Un index inutile fera gonfler la taille du segment des index, mais perturbera aussi le cache pour sa gestion car il faudra y stocker les pages mises à jour, au détriment d'autres objets.



La mémoire cache est un élément fondamental dans une base 4D ; il est important de bien la paramétrer en fonction de l'usage de la base. Trop peu de mémoire cache et le moteur ne pourra pas bénéficier de ses effets bénéfiques ; trop de mémoire cache peut dans certains cas asphyxier le moteur et provoquer des effets indésirables ! Comme toujours, l'art du développement consiste à trouver le juste équilibre dans ses choix.

 

RSS 0 commentaire(s) pour ce billet

Poster un nouveau commentaire

  • Les adresses de pages web et de messagerie électronique sont transformées en liens automatiquement.
  • You may use [view:viewname] tags to display listings of nodes.
  • Each email address will be obfuscated in a human readable fashion or (if JavaScript is enabled) replaced with a spamproof clickable link.

Plus d'informations sur les options de formatage