Représentation mémoire Skander Zannad et Judicaël Courant 2014-10-07 1 Modèle mémoire Représentation des données en mémoire : – Relativement complexe. – Mais on peut travailler sur un modèle relativement simple. Notre modèle : – Python manipule des données qu’on appelle des objets. – Un objet est une suite de cases mémoires contiguës contenant 1. Le type de l’objet. 2. Des données propres à l’objet. 3. Des liens vers d’autres objets (adresses des autres objets). 1 Exemple : str [ 1 , 2 , ’ s o l e i l ’ , [42 , 17]] a int list int dict 123 47162136380880 1 32464192 str 47162136380920 b 32461144 int 32739896 32461120 2 47162136379840 int 47162137268952 1789 47162137342672 47162137217576 str str soleil t list int 32462152 42 32460760 list str 47162137342720 hello 47162137342768 int str 17 world 3 Affectation 2 Variables globales Quand on définit des variables (globales), Modifions a : celles-ci sont stockées dans une table appe- a = b lée dictionnaire associant à chaque nom de Que s’est-il passé ? variable sa valeur : 1. On a évalué l’expression b. Le résula = 123 tat est une adresse mémoire, celle de b = 1789 l’entier 1789. t = [ ’ h e l l o ’ , ’ world ’ ] 2. Ce résultat est mis dans a. str dict a 47162136380880 int 32739896 1789 47162136380920 32739896 str 47162136379840 b 47162137268952 str t list str 47162137342720 hello 47162137342768 str world 2 4 Expressions str a a = b + 1 Pour évaluer 1789 + 1, Python construit un nouvel objet, y met le résultat et retourne son adresse. L’évaluation d’une expression peut créer de nouveaux objets. int dict 1789 47162136380880 32739536 str 47162136380920 b 32739896 47162136379840 int 47162137268952 1789 str str a t dict 47162136380880 int list str 47162137342720 hello 1790 32582232 str 47162136380920 b 47162137342768 str 32739896 world 47162136379840 int 47162137268952 1789 5 Aliasing str t list str 47162137342720 hello Deux variables peuvent représenter le même objet : 47162137342768 str t = [9283 , 1009] u = t world On parlera d’égalité physique pour dire que deux objets ont la même adresse mémoire. a = b + 0 En python, elle peut se tester avec le motPython a construit un nouvel objet pour clé is («t is u» vaut ici True). évaluer 1789 + 0. . . Remarque : Python n’est pas très malin dict str 47162136383280 u 47162137247256 47162136379840 list int 47162137247256 32739848 9283 32739824 int str 1009 t Cela peut avoir des conséquences inattendues : t [0 ] = 42 # u [ 0] v a u t maintenant 4 2 . . . 3 dict str str 47162136383280 u u 47162137247256 dict 47162136379840 list int 47162137247256 32462152 42 47162136383280 47162137268952 32739824 47162136379840 int str 47162137247256 1009 list 32739848 32739824 str int 9283 t t list 32739848 Attention : deux objets peuvent avoir le même contenu mais ne pas être physiquement égaux. t = [9283 , 1009] u = [9283 , 1009] int 1009 32739824 7 Un problème d’aliasing On parlera d’égalité structurelle. En python, elle se teste avec le symbole «==» («t == u» # m a t r i c e n u l l e 4∗3 vaut ici True alors que «t is u» vaut False) A = [[0]∗3]∗4 str u dict 47162136383280 47162137269960 47162136379840 list 47162137246104 list 47162137246104 32739848 32739824 47162137268952 str 47162137246104 int 47162137246104 9283 list 32461168 32461168 int 32461168 0 t list 32739848 int 1009 32739824 A [ 0 ] [ 2 ] = 42 list 6 Copier une liste 47162137246104 47162137246104 Le slicing (tranchage) se fait par copie. C’est un moyen simple de copier une liste dans une autre : 47162137246104 47162137246104 list 32461168 int 32461168 0 32462152 int t = [9283 , 1009] u = t[:] 42 4 Pour construire A correctement, on crée une liste de 4 objets bidons : A = [ None ]∗4 list 9653152 9653152 None 9653152 9653152 Puis on remplace chacun par une nouvelle rangée de 0. f o r i in range ( 4 ) : A [ i ] = [0]∗3 list 32461168 32461168 32461168 list list 47162137246104 32461168 47162137269960 32461168 47162137299280 32461168 47162137299568 list 32461168 int 0 32461168 32461168 list 32461168 32461168 32461168 5 8 Appel de fonctions Selon les langages de programmation, les valeurs des objets peuvent être : – Les données contenues dans les objets manipulés (cas de Scilab) – Les adresses en mémoire de ces objets (cas de Python) Appel de f(t), où t tableau à n éléments : – En Scilab, copie des n éléments : demande un temps proportionnel à n (long quand n est grand). Impossibilité pour f de modifier le contenu de t. – En Python, passage de l’adresse mémoire de t à f : temps constant. Possibilité pour f de modifier le contenu de t. 6 Exemple : int def swap ( u , i , j ) : u[i] , u[j] = u[j] , u[i] t = [ 11 , 22 , 33] swap ( t , 0 , 1) 32461168 int 32461144 1 47162137268952 Lors de l’exécution de swap, deux dictionnaires de variables : locales et globales. str 47162135947904 list int 32461096 3 32461072 47162137247256 int 4 NB : print(u) donne i dict 0 list [0 , 1 , [3 , 4 , [ . . . ] ] ] int 0 32461168 str 47162136381640 j 10 Ramasse-miettes 32461144 47162136383280 int 47162137299496 1 Pour exécuter t = [ 0 , 1 , 2] str dict 47162137299496 Python prend de la place mémoire pour représenter la liste : u 47162136379840 int list 22 32460640 32460904 int dict str 32460376 11 47162136379840 t 47162137299856 int str int list t 33 32461168 0 32461144 int 32461120 1 int 2 9 Graphe des données Lors de l’exécution du programme, les Si on affecte la variable avec une autre données peuvent former un graphe arbi- valeur : trairement complexe, il peut même y avoir t = 42 des cycles. u = [ 0 , 1 , 2] v = [3 , 4 , u] u [2] = v 7 dict str 47162136379840 t 32462152 int 42 Qu’est devenue la liste [0, 1, 2] ? – Elle n’est plus accessible depuis les variables existantes. – On peut libérer la place utilisée pour la liste afin de la réutiliser pour autre chose. 8 Récupération de la place inutilement utilisée : – Gérée par un mécanisme interne à l’implantation de Python. – Appelé Garbage Collector (GC), en français Glaneur de Cellules ou Ramasse-miettes. – Le déclenchement du GC est non spécifié : il peut aussi bien se déclencher dès qu’un objet est inaccessible qu’attendre le moment où la mémoire est pleine et où il faut faire de la place pour de nouveaux objets. 11 Conclusion Une bonne nouvelle : Python libère libère tout seul la mémoire qui n’est plus utilisée, donc il n’y a (presque) pas à s’en soucier. Une mauvaise : Quand on gère des données un peu complexes (tableaux de tableaux), il est important de comprendre la représentation des objets en mémoire pour comprendre ce qu’il se passe. Mais heureusement, comprendre ce qu’il se passe est facile si on apprend et qu’on retient les deux règles d’or. Les deux règles d’or : 1. Affecter une variable avec une expression associe la valeur de l’expression à la variable, appeler une fonction associe la valeur des expressions données comme arguments réels de la fonction aux variables paramètres formels de la fonction. 2. La valeur d’une expression est juste l’adresse mémoire de l’objet calculé par l’évaluation de l’expression. 9