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

Problème d'allocation

15 réponses
Avatar
JKB
Bonjour à tous,

Je suis parfaitement débutant en C++ (mais j'essaye de faire des
efforts). Je parle courament C et Fortran depuis de nombreuses
années...

J'utilise à partir d'un programme C/Fortran la libboost. Depuis que
j'ai porté ce code sous Solaris, j'ai des problèmes de mémoire
(free() sous Solaris rend la mémoire à l'application et non au
système, ce qui peut poser des problèmes...).

Je fais donc la course au gaspillage mémoire inutile et surtout,
j'essaye de libérer la mémoire dès qu'elle ne sert plus. Pour ce
faire, je vire autant que faire se peut toute variable statique
inutile, tout couple malloc/free pour les remplacer par des
mmap/munmap (mémoire effectivement libérée par Solaris).

Problème : j'ai un wrapper à la libboost qui a été écrit en C++ et
que j'ai déjà modifié malgré mes faibles compétences C++.
J'ai quelque chose uqi ressemble à une allocation :

static graph_t graph(num_nodes);

J'ai l'impression qu'il s'agit d'une allocation d'un tableau de
structure. num_nodes est un entier tout bête. Dans mon bouquin de
C++, on me dit qu'un tableau est déclaré sous la forme :

static graph_t graph[num_nodes];

Première question : quelle est la différence entre ces deux
syntaxes ?

Deuxième question : je sais utiliser mmap/munmap depuis le C. Est-ce
que je peux utiliser la même chose en C++ ? Sinon, comment faire ?
En fait, il faut absolument que je libère ce truc qui me consomme
700 Mo de mémoire :-(

Cordialement,

JKB

--
Le cerveau, c'est un véritable scandale écologique. Il représente 2% de notre
masse corporelle, mais disperse à lui seul 25% de l'énergie que nous
consommons tous les jours.

10 réponses

1 2
Avatar
pjb
JKB writes:

Bonjour à tous,

Je suis parfaitement débutant en C++ (mais j'essaye de faire des
efforts). Je parle courament C et Fortran depuis de nombreuses
années...

J'utilise à partir d'un programme C/Fortran la libboost. Depuis que
j'ai porté ce code sous Solaris, j'ai des problèmes de mémoire
(free() sous Solaris rend la mémoire à l'application et non au
système, ce qui peut poser des problèmes...).

Je fais donc la course au gaspillage mémoire inutile et surtout,
j'essaye de libérer la mémoire dès qu'elle ne sert plus. Pour ce
faire, je vire autant que faire se peut toute variable statique
inutile, tout couple malloc/free pour les remplacer par des
mmap/munmap (mémoire effectivement libérée par Solaris).

Deuxième question : je sais utiliser mmap/munmap depuis le C. Est-ce
que je peux utiliser la même chose en C++ ? Sinon, comment faire ?
En fait, il faut absolument que je libère ce truc qui me consomme
700 Mo de mémoire :-(



Pourquoi?

Il faudrait vraiment que tu nous explique cette extraordinaire
affirmation que le fait de ne pas rendre la mémoire au système pose
problème.

De deux choses, trois:

- ou bien la mémoire sera utilisée de nouveau par l'application et
alors il serait ridicule de la rendre au système pour la lui
redemander tout de suite après.

- ou bien la mémoire n'est plus utilisée par l'application et le
système n'en a pas besoin et alors à quoi ça sert de la lui rendre?

- ou bien la mémoire n'est plus utilisée par l'application et le
système en a besoin (pour lui ou pour une autre application) et
alors il va swapper la mémoire non utilisée et reprendre les pages
de RAM.


Dans tous le cas, je ne vois pas l'intérêt de rendre la mémoire au
système.

Alors, es tu bien sur d'être dans un cas où c'est nécessaire?


Problème : j'ai un wrapper à la libboost qui a été écrit en C++ et
que j'ai déjà modifié malgré mes faibles compétences C++.
J'ai quelque chose uqi ressemble à une allocation :

static graph_t graph(num_nodes);

J'ai l'impression qu'il s'agit d'une allocation d'un tableau de
structure. num_nodes est un entier tout bête. Dans mon bouquin de
C++, on me dit qu'un tableau est déclaré sous la forme :

static graph_t graph[num_nodes];

Première question : quelle est la différence entre ces deux
syntaxes ?



Dans le second cas, la mémoire est allouée au lancement du programme,
comme mémoire statique. num_nodes * sizeof(graph_t) octets sont
alloués. Cette mémoire n'est pas libérée, tant que le processus n'est
pas tué ou qu'il ne fasse un exec(2) ou similaire.


Dans le premier cas, on ne peut que faire des suppositions, car il
s'agit soit de l'appel au constructeur de la classe graph_t (si c'en
est une), soit de l'appel à la fonction graph (si c'en est une), et
dans ces deux cas, il peut se produire n'importe quoi selon ce qui est
programmé dans ces fonctions.



--
__Pascal Bourguignon__ http://www.informatimago.com/

IMPORTANT NOTICE TO PURCHASERS: The entire physical universe,
including this product, may one day collapse back into an
infinitesimally small space. Should another universe subsequently
re-emerge, the existence of this product in that universe cannot be
guaranteed.
Avatar
Fabien LE LEZ
On Sat, 04 Oct 2008 15:03:11 +0200, (Pascal J.
Bourguignon):

- ou bien la mémoire n'est plus utilisée par l'application et le
système en a besoin (pour lui ou pour une autre application) et
alors il va swapper la mémoire non utilisée



Cela ne suppose-t-il pas d'écrire 700 Mo de données sur disque dur ?
Ça peut prendre un bout de temps, et ralentir les autres opérations
disque.
Avatar
Fabien LE LEZ
On Sat, 4 Oct 2008 10:53:16 +0000 (UTC), JKB
:

Problème : j'ai un wrapper à la libboost qui a été écrit en C++ et
que j'ai déjà modifié malgré mes faibles compétences C++.
J'ai quelque chose uqi ressemble à une allocation :

static graph_t graph(num_nodes);



Déclaration et définition d'un objet "graph" de type "graph_t".
L'équivalent en pseudo-C serait :

static graph_t graph;
graph.constructeur (num_nodes);

La première opération n'alloue que sizeof(graph_t) octets, ce qui
n'est probablement pas beaucoup.
La deuxième est un appel à une fonction (le constructeur), qui peut
faire tout ce que fait une fonction normale, y compris allouer
dynamiquement de la mémoire. Faut regarder la doc de graph_t pour
savoir ce que ce constructeur fait effectivement.


Dans mon bouquin de
C++, on me dit qu'un tableau est déclaré sous la forme :

static graph_t graph[num_nodes];



C'est une syntaxe partiellement héritée du C.


Deuxième question : je sais utiliser mmap/munmap depuis le C. Est-ce
que je peux utiliser la même chose en C++ ? Sinon, comment faire ?
En fait, il faut absolument que je libère ce truc qui me consomme
700 Mo de mémoire :-(




Quel est ton problème exactement ? Tu dois gérer plus de 2 Go sur un
système 32 bits ? On est quand même en 2008 ; on pourrait croire que
les développements qui ont vraiment besoin du 64 bits se font en 64
bits.

'fin bon, si tu veux transformer l'énorme allocation effectuée par
"static graph_t graph(num_nodes);" en un mmap(), va falloir aller voir
le code du constructeur de graph_t.
Avatar
JKB
Le 04-10-2008, ? propos de
Re: Problème d'allocation,
Pascal J. Bourguignon ?crivait dans fr.comp.lang.c++ :
JKB writes:

Bonjour à tous,

Je suis parfaitement débutant en C++ (mais j'essaye de faire des
efforts). Je parle courament C et Fortran depuis de nombreuses
années...

J'utilise à partir d'un programme C/Fortran la libboost. Depuis que
j'ai porté ce code sous Solaris, j'ai des problèmes de mémoire
(free() sous Solaris rend la mémoire à l'application et non au
système, ce qui peut poser des problèmes...).

Je fais donc la course au gaspillage mémoire inutile et surtout,
j'essaye de libérer la mémoire dès qu'elle ne sert plus. Pour ce
faire, je vire autant que faire se peut toute variable statique
inutile, tout couple malloc/free pour les remplacer par des
mmap/munmap (mémoire effectivement libérée par Solaris).

Deuxième question : je sais utiliser mmap/munmap depuis le C. Est-ce
que je peux utiliser la même chose en C++ ? Sinon, comment faire ?
En fait, il faut absolument que je libère ce truc qui me consomme
700 Mo de mémoire :-(



Pourquoi?

Il faudrait vraiment que tu nous explique cette extraordinaire
affirmation que le fait de ne pas rendre la mémoire au système pose
problème.

De deux choses, trois:

- ou bien la mémoire sera utilisée de nouveau par l'application et
alors il serait ridicule de la rendre au système pour la lui
redemander tout de suite après.

- ou bien la mémoire n'est plus utilisée par l'application et le
système n'en a pas besoin et alors à quoi ça sert de la lui rendre?

- ou bien la mémoire n'est plus utilisée par l'application et le
système en a besoin (pour lui ou pour une autre application) et
alors il va swapper la mémoire non utilisée et reprendre les pages
de RAM.


Dans tous le cas, je ne vois pas l'intérêt de rendre la mémoire au
système.

Alors, es tu bien sur d'être dans un cas où c'est nécessaire?



Oui, parce que cette allocation prend 1,5 Go de mémoire, que le code
fait un fork() pour une sombre histoire de surveillance de processus
et de cloture de pipes et que je ne vois aucune raison de traîner
1,5 Go de mémoire dans un processus qui devrait faire au plus
quelques Mo. Le problème est que cette non libération de données
inutiles provoque un doublement de l'espace mémoire occupé et que la
machine qui fait tourner le truc swappe non pas parce qu'elle n'a
pas assez de mémoire physique, mais parce qu'elle passe son temps à
coller dans le swap ces données inutiles à la moitié des processus.

Problème : j'ai un wrapper à la libboost qui a été écrit en C++ et
que j'ai déjà modifié malgré mes faibles compétences C++.
J'ai quelque chose uqi ressemble à une allocation :

static graph_t graph(num_nodes);

J'ai l'impression qu'il s'agit d'une allocation d'un tableau de
structure. num_nodes est un entier tout bête. Dans mon bouquin de
C++, on me dit qu'un tableau est déclaré sous la forme :

static graph_t graph[num_nodes];

Première question : quelle est la différence entre ces deux
syntaxes ?



Dans le second cas, la mémoire est allouée au lancement du programme,
comme mémoire statique. num_nodes * sizeof(graph_t) octets sont
alloués. Cette mémoire n'est pas libérée, tant que le processus n'est
pas tué ou qu'il ne fasse un exec(2) ou similaire.


Dans le premier cas, on ne peut que faire des suppositions, car il
s'agit soit de l'appel au constructeur de la classe graph_t (si c'en
est une), soit de l'appel à la fonction graph (si c'en est une), et
dans ces deux cas, il peut se produire n'importe quoi selon ce qui est
programmé dans ces fonctions.



Le graph_t est déclaré comme suit :

typedef adjacency_list < listS, vecS, directedS, Vertex, Edge> graph_t;

J'avoue que cela ne m'aide pas...

JKB

--
Le cerveau, c'est un véritable scandale écologique. Il représente 2% de notre
masse corporelle, mais disperse à lui seul 25% de l'énergie que nous
consommons tous les jours.
Avatar
JKB
Le 04-10-2008, ? propos de
Re: Problème d'allocation,
Fabien LE LEZ ?crivait dans fr.comp.lang.c++ :
On Sat, 4 Oct 2008 10:53:16 +0000 (UTC), JKB
:

Problème : j'ai un wrapper à la libboost qui a été écrit en C++ et
que j'ai déjà modifié malgré mes faibles compétences C++.
J'ai quelque chose uqi ressemble à une allocation :

static graph_t graph(num_nodes);



Déclaration et définition d'un objet "graph" de type "graph_t".
L'équivalent en pseudo-C serait :

static graph_t graph;
graph.constructeur (num_nodes);

La première opération n'alloue que sizeof(graph_t) octets, ce qui
n'est probablement pas beaucoup.
La deuxième est un appel à une fonction (le constructeur), qui peut
faire tout ce que fait une fonction normale, y compris allouer
dynamiquement de la mémoire. Faut regarder la doc de graph_t pour
savoir ce que ce constructeur fait effectivement.


Dans mon bouquin de
C++, on me dit qu'un tableau est déclaré sous la forme :

static graph_t graph[num_nodes];



C'est une syntaxe partiellement héritée du C.


Deuxième question : je sais utiliser mmap/munmap depuis le C. Est-ce
que je peux utiliser la même chose en C++ ? Sinon, comment faire ?
En fait, il faut absolument que je libère ce truc qui me consomme
700 Mo de mémoire :-(




Quel est ton problème exactement ? Tu dois gérer plus de 2 Go sur un
système 32 bits ? On est quand même en 2008 ; on pourrait croire que
les développements qui ont vraiment besoin du 64 bits se font en 64
bits.

'fin bon, si tu veux transformer l'énorme allocation effectuée par
"static graph_t graph(num_nodes);" en un mmap(), va falloir aller voir
le code du constructeur de graph_t.



Je veux pouvoir le libérer si besoin. Maintenant, je suis sur des
machines massivement parallèles (64 procs, 64 bits, 64 Go de
mémoire [seulement] aujourd'hui et avec un OS 64 bits) et je lance des
calculs d'optimisation sur des cartographies à l'échelle d'un pays.
Chaque calcul élémentaire nécessite le calcul de plusieurs centaines
de trajets dans la cartographie _complète_. J'utilise aussi à des
fins de développement du 32 bits avec le même OS (moins de mémoire
et moins de procs) et le problème reste le même. À l'extrême limite,
ça pourrait très bien fonctionner entièrement en 32 bits,
puisqu'aucun processus ne consomme plus de 1,5 Go.

Par ailleurs, ces processus sont _indépendants_ entre eux.

Je ne peux pas me permettre que chaque processus me prenne 2 * 1,5
Go de mémoire pour seulement 1,5 Go utile. J'en suis donc à
optimiser l'utilisation de la mémoire au mieux pour éviter que ça
swappe.

JKB

--
Le cerveau, c'est un véritable scandale écologique. Il représente 2% de notre
masse corporelle, mais disperse à lui seul 25% de l'énergie que nous
consommons tous les jours.
Avatar
JKB
Le 04-10-2008, ? propos de
Re: Problème d'allocation,
JKB ?crivait dans fr.comp.lang.c++ :
Le 04-10-2008, ? propos de
Re: Problème d'allocation,
Fabien LE LEZ ?crivait dans fr.comp.lang.c++ :
On Sat, 4 Oct 2008 10:53:16 +0000 (UTC), JKB
:

Problème : j'ai un wrapper à la libboost qui a été écrit en C++ et
que j'ai déjà modifié malgré mes faibles compétences C++.
J'ai quelque chose uqi ressemble à une allocation :

static graph_t graph(num_nodes);



Déclaration et définition d'un objet "graph" de type "graph_t".
L'équivalent en pseudo-C serait :

static graph_t graph;
graph.constructeur (num_nodes);

La première opération n'alloue que sizeof(graph_t) octets, ce qui
n'est probablement pas beaucoup.
La deuxième est un appel à une fonction (le constructeur), qui peut
faire tout ce que fait une fonction normale, y compris allouer
dynamiquement de la mémoire. Faut regarder la doc de graph_t pour
savoir ce que ce constructeur fait effectivement.


Dans mon bouquin de
C++, on me dit qu'un tableau est déclaré sous la forme :

static graph_t graph[num_nodes];



C'est une syntaxe partiellement héritée du C.


Deuxième question : je sais utiliser mmap/munmap depuis le C. Est-ce
que je peux utiliser la même chose en C++ ? Sinon, comment faire ?
En fait, il faut absolument que je libère ce truc qui me consomme
700 Mo de mémoire :-(




Quel est ton problème exactement ? Tu dois gérer plus de 2 Go sur un
système 32 bits ? On est quand même en 2008 ; on pourrait croire que
les développements qui ont vraiment besoin du 64 bits se font en 64
bits.

'fin bon, si tu veux transformer l'énorme allocation effectuée par
"static graph_t graph(num_nodes);" en un mmap(), va falloir aller voir
le code du constructeur de graph_t.



Je veux pouvoir le libérer si besoin. Maintenant, je suis sur des
machines massivement parallèles (64 procs, 64 bits, 64 Go de
mémoire [seulement] aujourd'hui et avec un OS 64 bits) et je lance des
calculs d'optimisation sur des cartographies à l'échelle d'un pays.
Chaque calcul élémentaire nécessite le calcul de plusieurs centaines
de trajets dans la cartographie _complète_. J'utilise aussi à des
fins de développement du 32 bits avec le même OS (moins de mémoire
et moins de procs) et le problème reste le même. À l'extrême limite,
ça pourrait très bien fonctionner entièrement en 32 bits,
puisqu'aucun processus ne consomme plus de 1,5 Go.

Par ailleurs, ces processus sont _indépendants_ entre eux.

Je ne peux pas me permettre que chaque processus me prenne 2 * 1,5
Go de mémoire pour seulement 1,5 Go utile. J'en suis donc à
optimiser l'utilisation de la mémoire au mieux pour éviter que ça
swappe.



Je viens de trouver un clear() qui semble vider le graph. Je vais de
ce pas tester... en espérant que cela rende la mémoire au système et
pas à l'application...

Cordialement,

JKB

--
Le cerveau, c'est un véritable scandale écologique. Il représente 2% de notre
masse corporelle, mais disperse à lui seul 25% de l'énergie que nous
consommons tous les jours.
Avatar
pjb
JKB writes:

Le 04-10-2008, ? propos de
Re: Problème d'allocation,
Pascal J. Bourguignon ?crivait dans fr.comp.lang.c++ :
JKB writes:

Bonjour à tous,

Je suis parfaitement débutant en C++ (mais j'essaye de faire des
efforts). Je parle courament C et Fortran depuis de nombreuses
années...

J'utilise à partir d'un programme C/Fortran la libboost. Depuis que
j'ai porté ce code sous Solaris, j'ai des problèmes de mémoire
(free() sous Solaris rend la mémoire à l'application et non au
système, ce qui peut poser des problèmes...).

[...]


Alors, es tu bien sur d'être dans un cas où c'est nécessaire?



Oui, parce que cette allocation prend 1,5 Go de mémoire, que le code
fait un fork() pour une sombre histoire de surveillance de processus
et de cloture de pipes et que je ne vois aucune raison de traîner
1,5 Go de mémoire dans un processus qui devrait faire au plus
quelques Mo.



Le processus de surveillance pourrait forker avant d'allouer la
mémoire. D'autre part, tu sais surement déjà que forker n'est pas
dupliquer la mémoire. C'est seulement la modification ultérieure de
la mémoire commune qui provoque la duplication. Est ce que ces
algorithmes modifient 1.5 Go de mémoire ?


Le problème est que cette non libération de données
inutiles provoque un doublement de l'espace mémoire occupé et que la
machine qui fait tourner le truc swappe non pas parce qu'elle n'a
pas assez de mémoire physique, mais parce qu'elle passe son temps à
coller dans le swap ces données inutiles à la moitié des processus.



Soit.


Dans le premier cas, on ne peut que faire des suppositions, car il
s'agit soit de l'appel au constructeur de la classe graph_t (si c'en
est une), soit de l'appel à la fonction graph (si c'en est une), et
dans ces deux cas, il peut se produire n'importe quoi selon ce qui est
programmé dans ces fonctions.



Le graph_t est déclaré comme suit :

typedef adjacency_list < listS, vecS, directedS, Vertex, Edge> graph_t;

J'avoue que cela ne m'aide pas...



Il y a plusieurs choses qui sont allouées. Les données appartenant
strictement à adjacency_list le sont selon la façon dont tu l'alloue.

new graph_t() --> alloué dynamiquement.
{ graph_t local; } --> alloué automatiquement sur la pile.
static graph_t global; --> alloué statiquement.

En même temps, l'allocation des éléments du graphe se fait selon les
classes utilisées, passées en paramètre au template. Il faut donc
aller voir le source de listS, vecS, etc.

Par exemple, si listS est une std::list, on peut faire en sorte
qu'elle ne soit pas allouée normalement par new/delete, en passant à
la template std::list un allocateur spécifique. Voir:

http://www.cplusplus.com/reference/stl/list/
http://www.cplusplus.com/reference/misc/memory/allocator/
http://www.bearcave.com/software/c++_mem.html

En particulier, cette dernière référence montre comment séparer
l'allocation d'un objet de sa "construction". On peut ainsi
facilement placer des objets dans la mémoire allouée par mmap.



--
__Pascal Bourguignon__ http://www.informatimago.com/

CONSUMER NOTICE: Because of the "uncertainty principle," it is
impossible for the consumer to simultaneously know both the precise
location and velocity of this product.
Avatar
Marc
JKB wrote:

Je viens de trouver un clear() qui semble vider le graph. Je vais de
ce pas tester... en espérant que cela rende la mémoire au système et
pas à l'application...



Il n'y a pas de raison, ça va juste faire un free. C'est l'allocateur
qu'il faut changer.

J'ai l'impression que vous cherchez plutôt une implémentation de
malloc/free utilisant mmap (et munmap) plutôt que sbrk à interposer
devant le malloc de la libc. Ça doit exister, mais je ne sais pas si une
des 15 implémentations de malloc livrées avec solaris le fait.
Avatar
JKB
Le 06-10-2008, ? propos de
Re: Problème d'allocation,
Marc ?crivait dans fr.comp.lang.c++ :
JKB wrote:

Je viens de trouver un clear() qui semble vider le graph. Je vais de
ce pas tester... en espérant que cela rende la mémoire au système et
pas à l'application...



Il n'y a pas de raison, ça va juste faire un free. C'est l'allocateur
qu'il faut changer.

J'ai l'impression que vous cherchez plutôt une implémentation de
malloc/free utilisant mmap (et munmap) plutôt que sbrk à interposer
devant le malloc de la libc. Ça doit exister, mais je ne sais pas si une
des 15 implémentations de malloc livrées avec solaris le fait.



C'est exactement ça et je n'ai pas trouvé. Je me demande même si ça
existe...

JKB

--
Le cerveau, c'est un véritable scandale écologique. Il représente 2% de notre
masse corporelle, mais disperse à lui seul 25% de l'énergie que nous
consommons tous les jours.
Avatar
espie
In article ,
JKB wrote:
J'ai l'impression que vous cherchez plutôt une implémentation de
malloc/free utilisant mmap (et munmap) plutôt que sbrk à interposer
devant le malloc de la libc. Ça doit exister, mais je ne sais pas si une
des 15 implémentations de malloc livrées avec solaris le fait.



C'est exactement ça et je n'ai pas trouvé. Je me demande même si ça
existe...

JKB



Marrant, en 10 minutes dans le code source de solaris, j'ai trouve une
implementation frustre, mais qui a l'air fonctionnelle mmapmalloc ou un
nom dans ce genre.
1 2