Deep EVM #2 : Modèle mémoire — Pile, mémoire, stockage et calldata
Engineering Team
Les quatre zones de données
L’EVM possède quatre zones distinctes où les données peuvent résider pendant l’exécution d’un contrat. Choisir la bonne zone est l’une des décisions les plus importantes pour l’optimisation du gas.
1. La pile
La pile est la zone de travail principale. Chaque élément fait 32 octets (256 bits). La profondeur maximale est de 1024 éléments. Les opcodes DUP et SWAP ne peuvent atteindre que 16 niveaux de profondeur.
Coût : 3 gas pour la plupart des opérations de pile (PUSH, DUP, SWAP, POP). C’est l’espace le moins cher, mais aussi le plus contraint.
2. La mémoire
La mémoire est un tableau d’octets linéaire, adressable par octet, qui commence vide à chaque contexte d’appel. Elle s’étend dynamiquement lorsque vous écrivez au-delà de sa taille actuelle.
Les opcodes clés : MSTORE (écrire 32 octets), MSTORE8 (écrire 1 octet), MLOAD (lire 32 octets), MSIZE (taille actuelle).
La formule d’expansion mémoire
Le coût du gas pour l’expansion mémoire est quadratique :
cout_memoire = 3 * nombre_mots + nombre_mots^2 / 512
Pour les petites allocations (< 724 octets), le coût est essentiellement linéaire à 3 gas par mot de 32 octets. Au-delà, le terme quadratique domine rapidement.
3. Le stockage
Le stockage est la seule zone persistante — les valeurs survivent entre les transactions. Organisé en paires clé-valeur de 32 octets chacune, mappées à l’adresse du contrat.
C’est de loin la zone la plus chère : SLOAD (2100 gas froid, 100 chaud), SSTORE (22100 gas pour écrire une nouvelle valeur non nulle).
4. Calldata
Calldata est une zone en lecture seule contenant les données envoyées avec la transaction. L’accès est bon marché : CALLDATALOAD coûte 3 gas pour lire 32 octets.
En Solidity, les paramètres de fonction marqués calldata (pour les types mémoire) restent dans cette zone et évitent une copie en mémoire.
Le pointeur de mémoire libre
Solidity maintient un « pointeur de mémoire libre » à la position 0x40. Ce pointeur suit la prochaine position mémoire disponible. Chaque allocation mémoire lit ce pointeur, l’utilise, et le met à jour.
assembly {
let ptr := mload(0x40) // Lire le pointeur libre
mstore(ptr, value) // Écrire à la position libre
mstore(0x40, add(ptr, 32)) // Mettre à jour le pointeur
}
En Yul et Huff, vous gérez la mémoire manuellement. Vous pouvez ignorer le pointeur libre et utiliser la mémoire à volonté — tant que vous n’écrasez pas des données dont vous avez encore besoin.
Disposition de la mémoire Solidity
Solidity réserve les premières positions mémoire :
- 0x00-0x3f : Espace scratch pour le hachage
- 0x40-0x5f : Pointeur de mémoire libre
- 0x60-0x7f : Slot zéro (utilisé comme valeur initiale pour les tableaux dynamiques)
- 0x80+ : Début de la mémoire libre
Comprendre cette disposition est essentiel lorsque vous écrivez du Yul inline dans Solidity — si vous écrasez 0x40 accidentellement, l’allocateur mémoire de Solidity produira des résultats corrompus.
Comparaison des coûts
| Opération | Zone | Gas |
|---|---|---|
| PUSH/DUP/SWAP | Pile | 3 |
| MLOAD/MSTORE | Mémoire | 3 + expansion |
| CALLDATALOAD | Calldata | 3 |
| SLOAD (froid) | Stockage | 2100 |
| SLOAD (chaud) | Stockage | 100 |
| SSTORE (froid, 0→non-zéro) | Stockage | 22100 |
Quand utiliser chaque zone
- Pile : Valeurs intermédiaires de calcul, compteurs de boucle, résultats temporaires. Limité à 16 de profondeur accessible.
- Mémoire : Données structurées (tableaux, structs), préparation des données de retour, paramètres d’appels inter-contrats.
- Stockage : État persistant du contrat — soldes, propriétaires, mappings.
- Calldata : Données d’entrée en lecture seule de la transaction. Préférez
calldataàmemorypour les paramètres de fonction quand c’est possible.
Conclusion
Les quatre zones de données de l’EVM ne sont pas interchangeables. Chacune a un profil de coût, une durée de vie et des contraintes d’accès distincts. Maîtriser quand utiliser la pile plutôt que la mémoire, quand lire le calldata plutôt que de copier en mémoire, et comment minimiser les accès au stockage — voilà la base de l’optimisation de gas.
Dans le prochain article, nous explorerons en détail le gas : pourquoi votre contrat coûte ce qu’il coûte, et comment réduire systématiquement ces coûts.