Twitter iPhone pliant OnePlus 11 PS5 Disney+ Orange Livebox Windows 11

A propos d'environnement

9 réponses
Avatar
jean-michel bain-cornu
Bonjour,

Voici une expérience tirée d'un cas concret rencontré aujourd'hui :

Que donne un "1000 in range(40000000)"
-sous windows XP ?
File "<console>", line 1, in ?
''' exceptions.MemoryError : '''
-sous linux ?
True

Dans les deux cas, la machine est très ralentie par le swap (serveurs
pas très récents avec 512 mo de RAM) mais ne se plante pas et reste
utilisable.

En dehors du pb de l'environnement, j'aimerais bien savoir pourquoi un
simple range prends autant de mémoire !

A+
jm

9 réponses

Avatar
hg
jean-michel bain-cornu wrote:

Evidemment, une liste de 40 000 000 objets, c'est un poil lourd... Tu
devrais regarder du côté de xrange:


Je n'ai pas vraiment besoin d'un range aussi gros, c'était pour le test.

Ce que je me demandais, c'est comment l'allocation de 40 millions
d'objets, quand même pas si gros que ça, peut déclencher une erreur de
mémoire sur un système peu chargé. Même si la RAM est saturée (et en
dehors du fait que l'OS prétend disposer de 217 millions d'octets
disponibles, soit environ 5,4 fois 40 millions...), la mémoire virtuelle
est là pour prendre le relais et devrait suffire.
En bref, le problème vient-il de l'implémentation de python sous
windows, ou de l'os lui-même ?


Il me semble que linux fait des allocations de 8K min.

hg


Avatar
Christophe
Bonjour,

Voici une expérience tirée d'un cas concret rencontré aujourd'hui :

Que donne un "1000 in range(40000000)"
-sous windows XP ?
File "<console>", line 1, in ?
''' exceptions.MemoryError : '''
-sous linux ?
True

Dans les deux cas, la machine est très ralentie par le swap (serveurs
pas très récents avec 512 mo de RAM) mais ne se plante pas et reste
utilisable.

En dehors du pb de l'environnement, j'aimerais bien savoir pourquoi un
simple range prends autant de mémoire !


Il va falloir relire la documentation de range : cette fonction
construit une liste contenant tous les enties entre 0 et n-1.

Utilise xrange à la place.

Avatar
Bruno Desthuilliers
Bonjour,

Voici une expérience tirée d'un cas concret rencontré aujourd'hui :

Que donne un "1000 in range(40000000)"
-sous windows XP ?
File "<console>", line 1, in ?
''' exceptions.MemoryError : '''
-sous linux ?
True

Dans les deux cas, la machine est très ralentie par le swap (serveurs
pas très récents avec 512 mo de RAM) mais ne se plante pas et reste
utilisable.

En dehors du pb de l'environnement, j'aimerais bien savoir pourquoi un
simple range prends autant de mémoire !


Parce que range() retourne une liste, peut-être ?-)

"""
Help on built-in function range in module __builtin__:

range(...)
range([start,] stop[, step]) -> list of integers

Return a list containing an arithmetic progression of integers.
"""

Evidemment, une liste de 40 000 000 objets, c'est un poil lourd... Tu
devrais regarder du côté de xrange:

"""
Help on class xrange in module __builtin__:

class xrange(object)
| xrange([start,] stop[, step]) -> xrange object
|
| Like range(), but instead of returning a list, returns an object
| that
| generates the numbers in the range on demand. For looping, this is
| slightly faster than range() and more memory efficient.
"""

Ou, plus simplement, utiliser les opérateurs de comparaison:

if 0 <= 1000 < 40000000:
print "bien plus efficace qu'avec range()"

HTH

Avatar
jean-michel bain-cornu
Evidemment, une liste de 40 000 000 objets, c'est un poil lourd... Tu
devrais regarder du côté de xrange:


Je n'ai pas vraiment besoin d'un range aussi gros, c'était pour le test.

Ce que je me demandais, c'est comment l'allocation de 40 millions
d'objets, quand même pas si gros que ça, peut déclencher une erreur de
mémoire sur un système peu chargé. Même si la RAM est saturée (et en
dehors du fait que l'OS prétend disposer de 217 millions d'octets
disponibles, soit environ 5,4 fois 40 millions...), la mémoire virtuelle
est là pour prendre le relais et devrait suffire.
En bref, le problème vient-il de l'implémentation de python sous
windows, ou de l'os lui-même ?

Avatar
Olivier Ravard
jean-michel bain-cornu wrote:
Evidemment, une liste de 40 000 000 objets, c'est un poil lourd... Tu
devrais regarder du côté de xrange:


Je n'ai pas vraiment besoin d'un range aussi gros, c'était pour le test.

Ce que je me demandais, c'est comment l'allocation de 40 millions
d'objets, quand même pas si gros que ça, peut déclencher une erreur de
mémoire sur un système peu chargé. Même si la RAM est saturée (et en
dehors du fait que l'OS prétend disposer de 217 millions d'octets
disponibles, soit environ 5,4 fois 40 millions...), la mémoire virtuelle
est là pour prendre le relais et devrait suffire.
En bref, le problème vient-il de l'implémentation de python sous
windows, ou de l'os lui-même ?
ça fait longtemps que j'ai remarqué ce fait. J'ai l'impression que windows

n'utilise pas la swap pour les allocations, ce qui est le cas sous Linux.
Je dirais que le "problème" (ou "particularité") est dû à l'OS plutôt
qu'à l'implémentation de Python sur l'OS.


Avatar
Christophe
Evidemment, une liste de 40 000 000 objets, c'est un poil lourd... Tu
devrais regarder du côté de xrange:


Je n'ai pas vraiment besoin d'un range aussi gros, c'était pour le test.

Ce que je me demandais, c'est comment l'allocation de 40 millions
d'objets, quand même pas si gros que ça, peut déclencher une erreur de
mémoire sur un système peu chargé. Même si la RAM est saturée (et en
dehors du fait que l'OS prétend disposer de 217 millions d'octets
disponibles, soit environ 5,4 fois 40 millions...), la mémoire virtuelle
est là pour prendre le relais et devrait suffire.
En bref, le problème vient-il de l'implémentation de python sous
windows, ou de l'os lui-même ?


Bah justement, ce n'est pas assez. Un int sur une archi 32bit c'est 4
octets. Ensuite, en Python la liste n'est pas un vecteur qui recopie les
objets mais un vecteur de pointeurs. Et donc sur une archi 32bit, il
faut ajouter 4 octets de plus à cause de la taille de la liste.
Résultat, il faut au minimum 8 octet par élément dans ta liste soit au
total 320 MB

Et ça, c'est pour une situation qui est encore loin de la réalité. En
Python, une liste ne connait pas le type des éléments qu'elle contient.
Donc chaque entier en plus de couter 4 octets lui même doit
obligatoirement inclure 4 octets de plus pour stocker un pointeur vers
le type de l'entier. On en est à 480 MB. Après, Python utilise un GC de
type refcount donc chaque objet inclue en plus 4 octets pour traiter le
compteur de reference donc crack, encore 80 MB dans les dents. Et pour
finir, cerise sur le gateau, il est très probable que l'allocation de
chaque entier soit allignée sur 8 octets ( les allocateurs font souvent
ça pour optimiser les perfs ).

Total : 1280 MB. Ca commence à faire lourd.


Avatar
jean-michel bain-cornu
Total : 1280 MB. Ca commence à faire lourd.
Effectivement.

Merci pour les infos en tous cas.

jm

Avatar
Christophe
Total : 1280 MB. Ca commence à faire lourd.
Effectivement.

Merci pour les infos en tous cas.


Il faut juste nuancer avec le fait que le dernier chiffre aurait du être
800 MB et pas 1280 MB ( erreur de calcul inside :D )


Avatar
jean-michel bain-cornu
Total : 1280 MB. Ca commence à faire lourd.
Effectivement.

Merci pour les infos en tous cas.


Il faut juste nuancer avec le fait que le dernier chiffre aurait du être
800 MB et pas 1280 MB ( erreur de calcul inside :D )
Ouaf, on est plus à ça près !