• Aucun résultat trouvé

´Etats de pointeur Un pointeur peut ˆetre dans les ´etats suivants:

N/A
N/A
Protected

Academic year: 2022

Partager "´Etats de pointeur Un pointeur peut ˆetre dans les ´etats suivants:"

Copied!
35
0
0

Texte intégral

(1)

Etats de pointeur ´

Un pointeur peut ˆetre dans les ´etats suivants:

NULL

: valeur sp ´eciale qui ne pointe sur rien

fou (dangling): l’objet point ´e n’existe plus

fuite (leak): l’objet point ´e n’est plus n ´ecessaire

normal

Les pointeurs fous et les fuites sont les deux probl `emes fondamentaux li ´es aux pointeurs.

(2)

Gestion m ´emoire

Allocation (facile) d ´esallocation (aha!) Comme les boˆıtes `a vitesse:

Automatique: la d ´esallocation est prise en charge par le langage

Manuelle: la d ´esallocation est `a la charge du programmeur

Semi-automatique: le langage v ´erifie les d ´esallocations Granularit ´e:

Par objet: chaque objet est allou ´e/d ´esallou ´e individuellement

(3)

Gestion m ´emoire manuelle en C

Deux fonctions de la biblioth `eque standard:

void *malloc (int n);

void free (void *ptr);

Fonctions typiquement implant ´ees en C; rien de sp ´ecial!

Utilisent des primitives du SE pour obtenir de la m ´emoire, e.g.

mmap

Ces fonctions partagent des informations administratives internes E.g. une free list de zones m ´emoire encore disponibles

free

peut avoir besoin de savoir combien de bytes sont lib ´er ´es

la taille

n

peut ˆetre stock ´ee par

malloc

juste avant les

n

bytes

(4)

Gestion m ´emoire par r ´egion

Au lieu de 2 op ´eration allouer N bytes et lib ´erer ces bytes:

region *region_new (void);

void *region_alloc (int n, region *r);

void region_free (region *r)

La cr ´eation de r ´egion parfois rec¸oit une information de taille

Un objet encore n ´ecessaire emp ˆeche toute sa r ´egion d’ ˆetre lib ´er ´ee

region alloc

plus efficace que

malloc

(5)

Gestion m ´emoire automatique

Comptage de r ´ef ´erences: `a chaque objet est associ ´e un compteur qui indique combien de pointeurs existent. Lorsque le compteur passe `a 0, on peut d ´esallouer l’objet.

GC (Glanage de Cellules ou plut ˆot Garbage Collection): `a partir des racines (i.e. les variables globales et la pile), traverser tous les

objets atteignables en passant par tous les pointeurs: les objets non-visit ´es peuvent ˆetre d ´esallou ´es.

R ´egions: une analyse sophistiqu ´ee du code d ´etermine dans quelle r ´egion allouer chaque objet, et `a quel moment d ´esallouer chaque r ´egion.

(6)

Compter les r ´ef ´erences

Chaque objet contient un champ refcnt

refcnt compte les r ´ef ´erences “entrantes” (qui pointent sur cet objet)

Copie resp. destruction de pointeur incr ´emente resp. d ´ecr ´emente refcnt Quand refcnt

= 0

:

D ´ecr ´ementer les refcnt des objets point ´es

Lib ´erer l’objet

Simple `a impl ´ementer, r ´ecup ´eration prompte, mais co ˆuteux

(7)

Difficult ´e de compter les r ´ef ´erences

Attention `a d ´ecr ´ementer apr `es incr ´ementer Co ˆut de tous ces incr ´ements et d ´ecr ´ements

Synchronizer les incr ´ements et d ´ecr ´ements en cas de concurrence Incapable de r ´ecuperer les cycles

(8)

Mark&Sweep

Chaque objet contient un markbit qui indique si l’objet est accessible Commencer par marquer tous les objets comme “inaccessibles”

Mark: Marquer r ´ecursivement tous les objets accessibles

Commencer par les racines

Suivre tous les pointeurs des objets rencontr ´es

Sweep: R ´ecup ´erer tous les objets encore marqu ´es “inaccessible”

(9)

Mark (&Sweep)

mark (ptr) {

if (!ptr->marked) {

ptr->marked = True;

for i = 0 to ptr->size mark (ptr[i]);

} }

mark_all () {

for varptr in roots mark (*varptr);

}

(10)

(Mark&) Sweep

sweep_all () {

ptr = heap_start;

do {

if (ptr->marked)

ptr->marked = False;

else

free_object (ptr);

} while (ptr = next_object (ptr))

}

(11)

Stop&Copy

Alloue un nouveau tas To aussi grand que le tas actuel From

alloc ptr indique quelle partie de To est encore libre

scan ptr indique quelle partie de To est termin ´ee

Copy: copier tous les objets accessibles de From dans To

Commencer par les racines

Copier les objets trouv ´es (cela fait avancer alloc ptr)

Placer un forwarding pointer de l’original vers la copie

Suivre tous les pointeurs entre scan ptr et alloc ptr

Une fois termin ´e, on peut lib ´erer From d’un seul coup d’un seul

(12)

(Stop&)Copy

copy (ptr) {

if (ptr->forward = NULL) { for i = 0 to ptr->size

alloc_ptr[i] = ptr[i];

ptr->forward = alloc_ptr;

alloc_ptr += ptr->size;

}

return ptr->forward;

}

(13)

Stop&Copy

stop&copy () {

alloc_ptr = scan_ptr = alloc_new_heap ();

for varptr in roots

*varptr = copy (*varptr);

while (scan_ptr < alloc_ptr) { for i = 0 to scan_ptr->size

scan_ptr[i] = copy (scan_ptr[i]);

scan_ptr += scan_ptr->size;

}

free_old_heap ();

}

(14)

Besoins du collecteur

Refcount Mark&Sweep Stop&Copy

champ refcnt (1-32bit) champ markbit (1bit) champ forward (1bit) Obtenir la taille de n’importe quel objet

Savoir quels champs contiennent des pointeurs inc/dec copie de ptr Liste de toutes les racines

Acc `es au tas Stop the world

(15)

Stop the world

mutateur: Le programme principal, qui fait le “travail utile”

collecteur: Le code qui s’occupe de r ´ecup ´erer la m ´emoire inutilis ´ee M&S et S&C sont tous deux des algorithmes stop the world:

Le mutateur doit ˆetre stopp ´e pendant que travaille le collecteur

(16)

Famille de GC

Un GC peut- ˆetre:

incr ´emental: chaque phase de GC est d ´ecoup ´ee en petite tranches

concurrent: mutateur et collecteur concurrents

parall `ele: collecteur divis ´es en plusieurs threads

partitionn ´e: le tas est divis ´e en sous-tas collect ´es ind ´ependamment

g ´en ´erationnel: GC partitionn ´e en sous-tas ordonn ´es par ˆage

distribu ´e: GC partitionn ´e sur des machines diff ´erentes

(17)

Finalization, pointeurs faibles

Les syst `emes `a base de GC offrent souvent la possibilit ´e de d ´etecter quand un objet est d ´esallou ´e:

Finalization: le programme sp ´ecifie qu’avant de d ´esallouer l’objet X, il faut ex ´ecuter la fonction F

Pointeur faible: pointeur qui n’emp ˆeche pas le GC de d ´esallouer l’objet point ´e. A chaque usage du pointeur, il faut v ´erifier s’il est encore vivant

Utilis ´es typiquement dans les caches, ou lors d’interaction avec des librairies externes que le GC ne comprend pas

Attention: la d ´esallocation n’a pas forc ´ement lieu

(18)

D ´esallocation manuelle

N ´ecessite des conventions et de la discipline E.g. biblioth `eque de table de hachage:

Dans

hash remove

, faut-il d ´esallouer la valeur enlev ´ee?

Dans

hash freetable

, faut-il aussi d ´esallouer les valeurs?

Dans

hash copytable

, que faut-il faire des valeurs?

Comment d ´esallouer les valeurs?

Pas de r ´eponses universellement id ´eales

(19)

D ´esallocation par ownership

1. Un des pointeurs de chaque objet est d ´esign ´e possesseur (owner) 2. L’objet est d ´esallou ´e lorsque son possesseur disparaˆıt

3.

Un pointeur n’est valide que si le possesseur est valide

Si l’invariant ne peut pas ˆetre pr ´eserv ´e:

Faire des copies, chaque copie a son propre possesseur

Ajouter un compteurs de r ´ef ´erences (compte nb de possesseurs)

Ajouter un pointeur dont le seul r ˆole est d’ ˆetre le possesseur Le possesseur peut changer au cours du temps

(20)

Gestion m ´emoire semi-automatique

Gestion manuelle:

Source intarissable de bugs graves

Frein au d ´eploiement de biblioth `eques Gestion automatique:

Pauses ind ´esirables pour usage temps-r ´eel

Parfois couteux, parfois inefficace

Contraintes fortes sur l’ensemble du syst `eme

(21)

Langage Rust

Sorte de m ´elange de Haskell et de C:

C: Langage de bas niveau

C: Gestion m ´emoire explicite

C: Langage imp ´eratif, avec r ´ef ´erences explicites

H: Encourage l’immutabilit ´e

H: Offre les types alg ´ebriques

H: Typage statique fort

H: Classes de type (appel ´ees Traits) [ Note: Exemples tir ´es du manuel de Rust ]

(22)

Syntaxe de Rust

Haskell Rust

f x y = e fn f (x : τ

1

, y : τ

2

) → τ {e}

let x = e

1

in e

2

let x = e

1

; e

2

if e then e

1

else e

2

if e then {e

1

} else {e

2

}

while e

1

{e

2

}

(23)

Ownership sur les chaˆınes

fn

main

() {

let s

1

=

String::from

( "hello" );

let s

2

= s

1

;

println!

( "s = {} " , s

2

);

}

Apr `es le

let s

2

= s

1

;

, la variable

s

1 n’est plus utilisable La chaˆıne est d ´esallou ´ee `a la fin de la fonction

(24)

Transfert d’ownership

fn

prs

(

mys

:

String

) {

println!

( "mys = {} " ,

mys

); } fn

main

() {

let s =

String::from

( "hello" );

prs

(s);

println!

( "s = {} " , s);

}

Erreur! La variable

s

n’est plus valide apr `es prs

(s);

(25)

Valeurs sans ownership

Certains types n’ont pas besoin de gestion m ´emoire:

fn

main

() {

let x

1

= 16;

let x

2

= x

1

;

println!

( "x = {} " , x

1

+ x

2

);

}

x

1 est encore valide apr `es

let x

2

= x

1

;

La diff ´erence est que les types entiers impl ´ementent le traits Copy

(26)

R ´ef ´erences et pr ˆets

Pour permettre acc `es sans transf ´erer le ownership

fn

prs

(

mys

:

&String

) {

println!

( "mys = {} " ,

mys

); }

fn

main

() {

let s =

String::from

( "hello" );

prs

(&s);

println!

( "s = {} " , s);

}

(27)

Morceaux de tableaux

Au lieu de pointeurs au milieu des tableaux, Rust offre les slices E.g. le type &str d ´ecrit une r ´ef ´erence sur une sous-chaˆıne:

fn

main

() {

let s :

String

=

String::from

( "Hello" );

let

sub

:

&str

= &s[0..4];

println!

( "sub = {} " ,

sub

);

}

(28)

Le type Option

Au lieu de NULL, utilise le type pr ´ed ´efini Option

enum

Option

<T > {

Some

(T ),

None

}

fn

plus one

(x :

Option

<

i32

>) →

Option

<

i32

> { match x {

None

None

,

Some(i)

Some

(i + 1)

} }

(29)

Contr ˆ ole des mutations

Rust impose un contr ˆole sur les modifications des objets

Pas de modifications via une r ´ef ´erence de type

&T

Une r ´ef ´erence de type

& mut T

permet les modifications

Une seule r ´ef ´erence de type

& mut T

`a la fois

Pas de

& mut T

et

&T

en m ˆeme temps

Pas de probl `emes caus ´es par des alias

(30)

The mot-cl ´e mut

Un objet de type Vec

<

i32

>

, est immuable Cependant:

fn fill_vec (v1: Vec<i32>) -> Vec<i32> { let mut v2 = v1;

v2.push(42);

v2 }

Le

let

a chang ´e le type en

mut

Vec

<

i32

>

(31)

Eviter les r ´ef ´erences folles? ´

fn

test

() →

&String

{

let s =

String::from

( "Hello" );

&s }

fn

main

() { let r =

test

(); }

La chaˆıne

s

est d ´esallou ´ee `a la fin de test

Le compilateur rejette le programme car

&s

survit son owner On peut renvoyer

s

`a la place (en ajustant le type de test)

(32)

Lifetimes

let s

1

=

String::from

( "Hello" );

let

result

{ let s

2

=

String::from

( "Goodbye" );

let l =

longest

(&s

1

, &s

2

);

result

= l;

Interdire result

= l;

pour ´eviter une r ´ef ´erence qui disparaˆıt trop tard!

Il faut d ´eterminer la lifetime de

l

:

(33)

Lifetimes explicites

La fonction longest doit explicitement d ´ecrire ses lifetimes:

fn

longest

<

’a

> (x :

&’a String

, y :

&’a String

) →

&’a String

{ if x.

len

() > y.

len

() then {x} else {y } }

Ces annotations de ’a indiquent:

Le lifetime de la valeur de retour est ´egale

au plus grand lifetime commun `a ceux de

x

et

y

conversion automatique de

&

’a

T

en

&

’b

T

(si ’b

<

’a) Sorte de sous-typage

(34)

Elision des lifetimes ´

En fait, toutes les r ´ef ´erences ont un type de la forme

&

’a

T

C’est la gestion et l’inf ´erence de ces lifetimes qui v ´erifie:

Un pointeur n’est valide que si le possesseur est valide R ´ef ´erences copiables vers un type avec une lifetime plus courte C¸ a prend un peu de pratique, mais:

La difficult ´e n’est pas artificielle: le m ˆeme probl `eme existe en C

Le compilateur Rust nous aide plus que les core-dump de C

(35)

Rust

Premier langage populaire d’une longue ligne de recherche

M ´elange inhabituel de fonctionalit ´es de haut-niveau et de bas-niveau Ownership utilis ´e pour:

Gestion m ´emoire: but original principal

Contr ˆoler la mutabilit ´e:

Eviter les probl `emes li ´es aux alias´

Plus important, ´eviter les conditions de courses

Références

Documents relatifs

9. Le récepteur peut être inséré dans le boîtier du pointeur pour les déplacements 10. Économie d’énergie avec le Auto- Standby et l’interrupteur Marche / Arrêt 13.

e coursename : afficher le nom d’un professeur le plus ancien souhaitant enseigner le cours coursename f filename : recopie la liste chaînée qui en résulte dans le

C’est pareil en langage C : changer *p dans une fonction (comme changer au poste 33 sur la télé-commande) permet de changer la valeur de la variable pointée (celle où le

4) Appuyez sur le bouton “Haut” pendant 2 secondes afin de faire une pause dans la présentation avec un écran noir. Appuyez à nouveau 2 secondes pour reprendre la

Deen, Analysis of transport phenomena, Oxford University Press, New York, 1998.. Roulet, Physique statistique, Hermann,

remarque 2 : si on tape 2+3, le tableur affichera 5. On peut ensuite taper ce que l’on désire, en tapant le nom des cellules ou en allant cliquer dessus avec la souris, et en

Le nom devient une r´ ef´ erence absolue ` a la cellule ou la plage de cellules, et peut ˆ etre utilis´ e comme tel dans les formules. a la place de

L’exemple suivant montre la déclaration d’une variable de type pointeur de fonction qui doit retourné un entier nommé pFonction1 et d’une fonction retournant