Forum |  HardWare.fr | News | Articles | PC | S'identifier | S'inscrire | Shop Recherche
1074 connectés 

  FORUM HardWare.fr
  Programmation
  C

  Questions sur la mémoire

 


 Mot :   Pseudo :  
 
Bas de page
Auteur Sujet :

Questions sur la mémoire

n°759851
jeremy
Posté le 10-06-2004 à 22:46:42  profilanswer
 

Salut,
 
Sous Linux, en C, j'analyse les programmes suivants avec la commande top pour savoir combien ils utilisent en RAM.
Je mets volontairement des variables énormes. Les scanf permettent juste de diviser en étapes.
Le but est de savoir quelle méthode consomme le moins de ressources, et comment est géré tout çà.
 
ESSAI 1 : variables locales
 

Code :
  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. extern int test1();
  4. extern int test2();
  5. extern int test3();
  6. int main(void){
  7.   int buf;
  8.   scanf("%d",&buf);
  9.   test1();
  10.   test2();
  11.   test3();
  12.   scanf("%d",&buf);
  13.   return 0;
  14. }


 

Code :
  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. int test1(){
  4.   char message[50000000]="";
  5.   strcpy(message,"salut1" );
  6.   return 0;
  7. }
  8. int test2(){
  9.   char message[50000000]="";
  10.   strcpy(message,"salut2" );
  11.   return 0;
  12. }
  13. int test3(){
  14.   char message[50000000]="";
  15.   strcpy(message,"salut3" );
  16.   return 0;
  17. }


 
On compile tout çà :
 
gcc -c essai1.c
gcc -c libessai1.c
gcc -o essai1 essai1.o libessai1.o

 
Le programme essai1 fait 14126 octets.
 
Résultat :
- avant appels aux fonctions test1, test2 et test3 : 0.1% MEM occupé
- après appels aux fonctions test1, test2 et test3 : 19.2% MEM occupé
 
Question : pourquoi la mémoire des variables locales (message) n'est pas détruite après les appels des fonctions ?
 
 
ESSAI 2 : variable globale
 

Code :
  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. extern int test1();
  4. extern int test2();
  5. extern int test3();
  6. extern char message[50000000];
  7. int main(void){
  8.   int buf;
  9.   scanf("%d",&buf);
  10.   test1();
  11.   test2();
  12.   test3();
  13.   scanf("%d",&buf);
  14.   printf("MESSAGE vaut : %s\n",message);
  15.   return 0;
  16. }


 

Code :
  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. char message[50000000]="";
  4. int test1(){
  5.   strcpy(message,"salut1" );
  6.   return 0;
  7. }
  8. int test2(){
  9.   strcpy(message,"salut2" );
  10.   return 0;
  11. }
  12. int test3(){
  13.   strcpy(message,"salut3" );
  14.   return 0;
  15. }


 
On compile tout çà :
 

gcc -c essai2.c
gcc -c libessai2.c
gcc -o essai2 essai2.o libessai2.o

 
Le programme essai2 fait 50014000 octets.
 
Résultat :
- avant appels aux fonctions test1, test2 et test3 : 0.1% MEM occupé
- après appels aux fonctions test1, test2 et test3 : 0.1% MEM occupé
 
Questions :
- pourquoi essai2 et libessai2.o sont si gros ?
- pourquoi on n'utilise toujours que 0.1% de la MEM, alors que la valeur de message est bien disponible lors du printf ?
 
Merci !


---------------
Savoir c'est vivre, et maintenir dans l'ignorance, c'est presque un homicide.
mood
Publicité
Posté le 10-06-2004 à 22:46:42  profilanswer
 

n°759877
el muchach​o
Comfortably Numb
Posté le 10-06-2004 à 23:13:29  profilanswer
 

Pour le 1, je ne sais pas, c'est peut-être dû à la gestion RAM /swap par Linux (?).
 
Pour la 2, tu fais une initialisation statique dans la librairie. La chaine est réservée et inscrite directement dans le code de la librairie (soit 5Mo + 14ko), qui est linkée statiquement avec ton programme principal et lue et recopiée en RAM au démarrage.
Peut-être qu'à ce moment là, il ne lit et n'alloue le tableau que jusqu'au premier '\0', càd l'octet 0. :sweat:
 
C'est une question pour Taz, ça.


Message édité par el muchacho le 10-06-2004 à 23:22:25
n°759889
jeremy
Posté le 10-06-2004 à 23:22:28  profilanswer
 

OK pour la 2, mais si la chaine est chargée en RAM au démarrage, pourquoi je n'ai que 0.1% qui est utilisée ? Je devrais avoir 19.2% (soit 50Mo) non ?


---------------
Savoir c'est vivre, et maintenir dans l'ignorance, c'est presque un homicide.
n°759897
el muchach​o
Comfortably Numb
Posté le 10-06-2004 à 23:28:42  profilanswer
 

Ben c'est pas clair. Je pense qu'il ne copie que jusqu'au premier '\0', mais pourquoi il n'allouerait pas les 50 Mo... j'avoue que je sèche.
 
T'as regardé si la swap n'avait pas grossi ?

n°759903
jeremy
Posté le 10-06-2004 à 23:38:16  profilanswer
 

Je crois ne pas avoir vu de modification de la swap.
Je vérifierai çà demain matin.
 
Merci & Bonne nuit !


---------------
Savoir c'est vivre, et maintenir dans l'ignorance, c'est presque un homicide.
n°759906
black_lord
Truth speaks from peacefulness
Posté le 10-06-2004 à 23:40:26  profilanswer
 

fait un memset de ta zone allouée et ça devrait gonfler :D

n°759907
jeremy
Posté le 10-06-2004 à 23:44:12  profilanswer
 

Déconne pas, çà je l'ai fait, effectivement çà a gonflé à 19.2%, mais je comprends pas la logique malgré tout.


---------------
Savoir c'est vivre, et maintenir dans l'ignorance, c'est presque un homicide.
n°759917
black_lord
Truth speaks from peacefulness
Posté le 10-06-2004 à 23:59:23  profilanswer
 

c'est que sous linux tant que la mémoire n'est pas réellement utilisée elle reste "dispo" comme ça quand tu fais la brute avec des gros mallocs pas de gaspillage.

n°759919
jeremy
Posté le 11-06-2004 à 00:02:45  profilanswer
 

Donc (dans le cas 2), c'est en fait alloué dynamiquement. A ce moment là, pourquoi avoir besoin de créer un exécutable énorme ?


---------------
Savoir c'est vivre, et maintenir dans l'ignorance, c'est presque un homicide.
n°759922
el muchach​o
Comfortably Numb
Posté le 11-06-2004 à 00:08:36  profilanswer
 

Oui.
 
Peut-être que le compilo considère que si tu lui passes la longueur, c'est que tu as une bonne raison.
 
Sinon, tu aurais dû en principe écrire :
char message[] = "Coucou";
 
Auquel cas, le code n'aurait fait que 7 octets supplémentaires.

mood
Publicité
Posté le 11-06-2004 à 00:08:36  profilanswer
 

n°759925
jeremy
Posté le 11-06-2004 à 00:13:27  profilanswer
 

Oki çà s'éclaire. Cette fois-ci je vais me pieuter et je verrais çà demain.
Bonne nuit.


---------------
Savoir c'est vivre, et maintenir dans l'ignorance, c'est presque un homicide.
n°759926
black_lord
Truth speaks from peacefulness
Posté le 11-06-2004 à 00:16:53  profilanswer
 

el muchacho a écrit :

Oui.
 
Peut-être que le compilo considère que si tu lui passes la longueur, c'est que tu as une bonne raison.
 
Sinon, tu aurais dû en principe écrire :
char message[] = "Coucou";
 
Auquel cas, le code n'aurait fait que 7 octets supplémentaires.


 
voila :jap:
 

  • le compilo fera dans le cas du statique une réservation de place où il mettra la variable (et tt son contenu)
  • ou bien il fait appel à une fonction de bibliothèque (malloc) qui réservera la mémoire. Pas besoin "d'embarquer" tout le "contenu" de la variable.


n°759931
red factio​n
Posté le 11-06-2004 à 00:30:14  profilanswer
 

alloue dynamiquement pour le 1 ?
 
je pensait que cetait plutot la pile dans ce cas qui etait utilisee...
 
dailleur ca metonne qu'on a pas un debordement de pile avec des tableau pareils
 
 
alloc dynamic c surttout a coup de malloc ou new non ?


Message édité par red faction le 11-06-2004 à 13:58:51
n°760066
jeremy
Posté le 11-06-2004 à 10:03:12  profilanswer
 

Pour le 2 ok.
Pour le 1 par contre, c'est pas très clair.
 
En fait le but de tout çà : les fonctions test1(), test2() et test3() doivent remplir un buffer à partir de leurs paramètres. Leurs paramètres sont des entiers et des chaines de longueur indéterminée, par exemple :
 

Code :
  1. int test1(char *chaine, int *entier, char *chaine2){
  2.   char chformat[]="Salut %s çà va %s";
  3.   ......
  4.   sprintf(buf,chformat,chaine,chaine2);
  5.   ......
  6.   bufferiser(buf);
  7.   ......
  8. }


 
Ce buffer sera vidé et envoyé par TCP/IP dans une autre fonction finale.
 
Alors je me demandais quelle méthode on doit prendre pour optimiser au maximum en terme de mémoire et d'occupation processeur :
 
- déclarer la variable locale buf en tant que chaine de longueur fixe ?
- déclarer la variable locale buf en tant que pointeur et l'allouer dynamiquement ?
et
- déclarer le buffer global en tant que variable globale de longueur fixe ?
- déclarer le buffer global en tant que pointeur alloué dynamiquement ?
 
ou encore autre chose ?
 
Merci !


---------------
Savoir c'est vivre, et maintenir dans l'ignorance, c'est presque un homicide.
n°760106
el muchach​o
Comfortably Numb
Posté le 11-06-2004 à 10:29:42  profilanswer
 

Pour le 1, essaye voir ce que donne la mémoire après un :  
message = "";
Ca m'étonnerait que ça retombe à 0, mais on ne sait jamais.
A mon avis, c'est une autre optimisation de la gestion mémoire de Linux, qui ne désallouerait réllement que s'il en a l'intérêt ou au bout d'un certains temps, un peu à la manière d'un garbage collector.
 
Pour ta question 2, je n'échangerais pas qualité de code pour un gain de vitesse la plupart du temps négligeable dans cette application (vu que de toute façon, les temps de latence réseau seront sans doute limitatifs).
 
Donc ma réponse est :
variable locale buf en tant que chaine de longueur fixe (tu introduis une contrainte supplémentaires sur la longueur des chaines) ou dynamique, selon tes besoins mémoire.
Après ça, si tu tiens vraiment à faire de l'optimisation vitesse (à vérifier avec des tests) et que tu connais d'avance le format de ta chaîne, n'utilise pas sprintf, qui est est un parseur, donc une usine à gaz (jette un oeil à son code), et construis-la à la main.


Message édité par el muchacho le 11-06-2004 à 10:35:31
n°760370
jeremy
Posté le 11-06-2004 à 12:59:53  profilanswer
 

Ok.
 
Mais si je n'utilise pas sprintf, je serais réduit à faire une série de strcat, sachant que certaines fonctions ont jusqu'à 8 paramètres, çà ferait beaucoup de strcat, c'est pas mieux qu'un seul sprintf... non ?
Et concernant la variable globale, statique ou dynamique ?


Message édité par jeremy le 11-06-2004 à 13:00:14

---------------
Savoir c'est vivre, et maintenir dans l'ignorance, c'est presque un homicide.
n°760496
el muchach​o
Comfortably Numb
Posté le 11-06-2004 à 14:36:04  profilanswer
 

Il y a de grosses chances que si, vu que chacun des paramètres est parsé. Mais pour tes deux questions, la seule réponse valable est : à toi de voir, teste pour te faire ta propre idée.

n°760536
HelloWorld
Salut tout le monde!
Posté le 11-06-2004 à 14:56:52  profilanswer
 

Au passage, scanf("%d",&buf); peut être remplacé par scanf("%*d" );
Pour le 1, je dirais qu'il s'agit de variables crées sur la pile, donc ton programme va essayer de réserver 50Mo sur la pile. Au départ, sa pile est beaucoup plus petite => exception, stack overflow, Linux réagit en faisant grossir la pile, et tout repart comme si de rien n'était. Sauf que ton programme possède une pile de 50Mo. Je trouve normal que l'OS fasse grossir la pile et ne la fasse pas rétrécir.
Moralité : allouer de grosses variables sur la pile c'est mal.
La taille initiale de la pile est normalement réglable dans les options de compialtion (linker).


---------------
FAQ fclc++ - FAQ C++ - C++ FAQ Lite
n°760553
jeremy
Posté le 11-06-2004 à 15:20:17  profilanswer
 

Donc si c'est mal, qu'est-ce que tu me conseilles :
 
- variable locale : taille fixe ou pointeur+malloc ? (moi je dirais dynamique)
- variable globale (buffer général) : taille fixe ou pointeur+malloc ?
 
Merci !


---------------
Savoir c'est vivre, et maintenir dans l'ignorance, c'est presque un homicide.
n°760566
HelloWorld
Salut tout le monde!
Posté le 11-06-2004 à 15:36:49  profilanswer
 

Pas de grosse variables sur la pile.
Gros tableaux locaux : malloc.
En global/static on s'en fout, c'est pas sur la pile.
Dans le cas 2, change char message[50000000]=""; en char message[50000000]; (non initialisé) et ton exe maigrit de 50Mo.
D'une manière générale j'aime pas les tailles fixes.
En informatique, y'a toujours des limites. Mettre une grosse taille repousse les limites, mais ne résoud pas le problème qu'elles peuvent être atteintes.
 
edit : petite coquille


Message édité par HelloWorld le 11-06-2004 à 15:37:13

---------------
FAQ fclc++ - FAQ C++ - C++ FAQ Lite
n°760592
red factio​n
Posté le 11-06-2004 à 15:55:46  profilanswer
 

le mieux si ta un gros tableau a utiliser c de lallouer qd ten a besoin a coup de new ou malloc...
 
edit : grilled de 20 min jetait parti bouffer et jai pas valider le msg


Message édité par red faction le 11-06-2004 à 15:56:34
n°760610
HelloWorld
Salut tout le monde!
Posté le 11-06-2004 à 16:19:47  profilanswer
 

Pas assez rapide petit scarabé !


---------------
FAQ fclc++ - FAQ C++ - C++ FAQ Lite
n°760624
jeremy
Posté le 11-06-2004 à 16:44:32  profilanswer
 

Bon.
Après quelques tests (sur programme réel en exploitation), je me dis qu'avoir des variables locales fixes (pas 50Mo je vous rassure :) : une chaine de 20000 octets çà vous parait gros ? ), c'est négligeable. Et surtout, sur un gros traitement, c'est plus rapide que de s'amuser à faire des malloc, étant donbné que pour allouer dynamiquement, il faut s'amuser à calculer la taille réelle de la chaine à chaque fois à coup de strlen.
 
Je crois donc que je vais privilégier les temps de réponse par rapport à un gain de mémoire qui serait, je pense, négligeable.
 
Merci à tous.
 
Je vous invite à lire : http://ilay.org/yann/articles/mem/


Message édité par jeremy le 11-06-2004 à 18:24:36

---------------
Savoir c'est vivre, et maintenir dans l'ignorance, c'est presque un homicide.
n°762165
HelloWorld
Salut tout le monde!
Posté le 13-06-2004 à 22:40:41  profilanswer
 

Moui.
Mais un tableau de taille fixe a une taille...fixe.
Que faire si ton tableau est trop petit ?


---------------
FAQ fclc++ - FAQ C++ - C++ FAQ Lite
n°762174
Taz
bisounours-codeur
Posté le 13-06-2004 à 22:44:52  profilanswer
 

HelloWorld a écrit :

Moui.
Mais un tableau de taille fixe a une taille...fixe.


mais un tableau a toujours une taille fixe

HelloWorld a écrit :


Que faire si ton tableau est trop petit ?

DTC. s'il existe des cas ou ton tableau va être trop petit il faut déjà le détecter et prévénir tout débordements, passer en dynamique si tu n'es pas capable de prévoir au pire tes besoins

n°762182
HelloWorld
Salut tout le monde!
Posté le 13-06-2004 à 22:51:44  profilanswer
 

Hum... tu as lu tout le post ?


---------------
FAQ fclc++ - FAQ C++ - C++ FAQ Lite
n°762188
Taz
bisounours-codeur
Posté le 13-06-2004 à 22:54:38  profilanswer
 

NON :D
 
ma réponse initiale c'était « plop, ça gaze »

n°762192
Taz
bisounours-codeur
Posté le 13-06-2004 à 22:58:04  profilanswer
 

« char chformat[]="Salut %s çà va %s"; »
 
fait gaffe là, tu cause 36 relocations pour rien. fais comme ça, fait un size ./a.out. maitenant rajoute un static const, refait un size, et tu vas voir !

n°762253
el muchach​o
Comfortably Numb
Posté le 13-06-2004 à 23:39:37  profilanswer
 

HelloWorld a écrit :

Moui.
Mais un tableau de taille fixe a une taille...fixe.
Que faire si ton tableau est trop petit ?


 
En plus c'est dangereux, parce que l'allocation statique de tableaux au debut d'un programme est brevete.  :lol: (Si si, c'est pas une blague, en plus ! :sweat: )
 
" Statically allocating an initial amount of memory when a program is first loaded according to a size value contained in the program header. [#5,247,674]."
http://www.base.com/software-patents/examples.html

mood
Publicité
Posté le   profilanswer
 


Aller à :
Ajouter une réponse
  FORUM HardWare.fr
  Programmation
  C

  Questions sur la mémoire

 

Sujets relatifs
[Visual Basic] utilisation d'un dll C++ && fuite memoireQuestions sur les signaux et alarmes
[CGI] - Petites questions ... je suis largué làRafraichissé moi la memoire, requete sql
[C] Pkoi mes fonctions prennent tant de place en mémoire?Questions php en anglais
2 questions sur Oracle, une limitation et une sauvegarde2 questions sur access (aide et feuille de données)
Recherche de string ds un bloc mémoire sans typeQuestions/Réponses sur l'informatique
Plus de sujets relatifs à : Questions sur la mémoire


Copyright © 1997-2022 Hardware.fr SARL (Signaler un contenu illicite / Données personnelles) / Groupe LDLC / Shop HFR