[C] Pourquoi cette perte de mémoire?

Pourquoi cette perte de mémoire? [C] - C - Programmation

Marsh Posté le 01-03-2004 à 12:24:31    

Bonjour à tous,
 
Je fait de la maintenance sur un programme C développé en Borland 3.1 sous DOS et je ne m'explique pas le phénomène suivant :  
 
une fonction lis un fichier texte qui contient des paires de noms -prénoms et alloue de l'espace mémoire dynamiquement. Chaque nom et prénom dans le fichier est composé de 22 caractères ( histoire de tester la capacité maximum de l'application), je m'attend donc qu'à chaque fois  la mémoire disponible diminue de ( 22 + 1) x 2 = 46 bytes or la différence entre un coreleft() avant et après l'allocation est de 64 unités... soit une différence de 18 bytes!
 
La fonction d'allocation actuelle :

Code :
  1. char* Alloc_String( char* String)
  2. {
  3.    char* Destination = new char [ strlen( String) + 1];
  4.    if ( Destination == NULL)
  5.    {
  6.       #if _DEBUGMODE
  7.          sprintf( gcDcio, "!!! Can't create new !!! String[%d] cleft[%lu]",
  8.             strlen( String) + 1, coreleft()); dcio();
  9.       #endif // _DEBUGMODE
  10.       Error_Exit( E_OUT_OF_MEMORY);
  11.    }
  12.    return strcpy( Destination, String);
  13. }


 
Ou est passé la différence? Est-il possible de l'éviter par exemple avec malloc()?


Message édité par avander le 01-03-2004 à 12:25:15
Reply

Marsh Posté le 01-03-2004 à 12:24:31   

Reply

Marsh Posté le 01-03-2004 à 12:30:33    

euh c'est un plaisanterie ?
 
le new là, c'est pour me faire un blague ?
 
 
mon remplace ton new par un malloc(strlen(String)+1);
 
et le pointeur que tu récupère comme ça
 
char *str = Alloc_String("dawa" );
 
oublie pas de faire un petit free dessus
 
free(str); en fin de programme
 
 
bingo, tu viens de réécrire la célèbre strdup
 
personnellement, j'aurais mémorié strlen pour faire un memcpy plutot qu'un strcpy

Reply

Marsh Posté le 01-03-2004 à 12:38:30    

Merci Taz,  
 
Désolé j'hérite de cette 'application', beaucoup de monde est déjà passé par là...  
 
Je me demandais aussi pourquoi un new ici et pas un malloc tout simplement ( pourquoi faire facile si on peut faire compliqué ;-), est-ce que la différence peut venir de là?  
 
Toutefaçon, je vais tester les différentes solutions y compris strdup() !

Reply

Marsh Posté le 01-03-2004 à 12:40:35    

new c'est du C++
 
moi je l'aurais écrite comme ça
 

Code :
  1. char *str_dup(const char *s)
  2. {
  3.   size_t len = strlen(s)+1;
  4.   char *new = malloc(len);
  5.   if(!new)
  6.     {
  7.       perror("malloc" );
  8.       /* peut-être un exit() ici */
  9.       return NULL;
  10.     }
  11.  
  12.   memcpy(new, s, len);
  13.   return new;
  14. }


 
strdup n'est pas forcément fournit par ton système en fait, mais regarde, ya sans doute des choses semblables

Reply

Marsh Posté le 01-03-2004 à 12:47:18    

si si strdup() est dispo, comprend pas pourquoi on réinvente la roue ici :-((
 
merci pour le ( joli) code. A+

Reply

Marsh Posté le 01-03-2004 à 16:50:37    

Après investigation un début de réponse, l'usage de new en non malloc ne semble pas être en cause.  
 
Lorsqu'on alloue un string d'un caractère on note que d'office on perd 16 bytes de mémoire, si on étend le string on observe une perte de 32 bytes dés que le string dépasse les 16...
 
Dans ce cas il est donc plus judicieux de ne pas allouer de string pour chaque champ séparement mais de leur allouer un espace mémoire commun dans lequel on les sépare à l'aide d'un caractère arbitraire. L'accès au champs individuels se fait alors à l'aide d'une fonction dédiée.
 
 
 

Reply

Marsh Posté le 01-03-2004 à 18:21:50    

non, c'est pas un bon raisonnement là, il est même stupide
l'allocateur mémoire alloue plus et il a parfaitement raison de le faire. si tu ne comprends pas, tant pis, mais ne va pas chercher des solutions à la noix pour par perdre un octet. ça serait stupide, long, et contre-performant
 
et puis tu fais tu C, alros utilise malloc et realloc


Message édité par Taz le 01-03-2004 à 18:25:22
Reply

Marsh Posté le 01-03-2004 à 23:04:17    

Avander a écrit :

Après investigation un début de réponse, l'usage de new en non malloc ne semble pas être en cause.  
 
Lorsqu'on alloue un string d'un caractère on note que d'office on perd 16 bytes de mémoire, si on étend le string on observe une perte de 32 bytes dés que le string dépasse les 16...
 
Dans ce cas il est donc plus judicieux de ne pas allouer de string pour chaque champ séparement mais de leur allouer un espace mémoire commun dans lequel on les sépare à l'aide d'un caractère arbitraire. L'accès au champs individuels se fait alors à l'aide d'une fonction dédiée.
 
 
 
 


 
et bien tu viens d'apprendre que les allocateurs ont toujours un pas d'allocation (et que de toutes manières les OS fontionnent en pages, de 4Ko ou 4Mo sur les x86), et accessoirement 16 octets ça fait un paragraph(e).

Reply

Marsh Posté le 02-03-2004 à 10:01:54    

Taz > Je suis d'accord avec toi pour dire que c'est pas idéal, et qu'il faut pas se préoccuper de la cuisine interne de l'allocateur mémoire, la modif que j'avance me permets toutefois de mieux utiliser la mémoire disponible, tous les noms sont chargés et il me reste encore... 25Ko alors qu'avant j'étais à court. Dans la pratique la fin justifie les moyens, hélas.  
 
bjone > Ben oui, je découvre... si tu as d'autres informations concernant ce sujet je suis preneur, est-ce que tu confirme mes conclusions?  
 

Reply

Marsh Posté le 02-03-2004 à 12:01:14    

vu que ton programme C est développé en Borland 3.1 sous DOS, tu as plusieurs choix:
 
1) utiliser des farmallocs, et te faire chier avec la segmentation des 64ko.
 
2) tu télécharges OpenWatcom ou DJGPP, et tu portes ton application en mode protégé appellé abusivement mode 32 bits.
 
d'un part tu pourras allouer juqu'à 64 mo de ram (limite des dos-extenders en général)
 
d'autre part, tu utilisesras un cpu actuel avec un meilleur rendement (le mode réel est l'ennemi des CPUs depuis le pentium pro)
 
et encore d'autre part, comme les routines de traitements auront été légèrement retouchés pour travailler avec un modèle mémoire "plat" (flat/linear, enfin non segmenté), ces routines seront presque portable telles quelles sour linux ou sous win32. (et genre insérer tes routines dans une appli graphique faite avec borland c++ builder pour faire un truc vite et propre)

Reply

Marsh Posté le 02-03-2004 à 12:01:14   

Reply

Marsh Posté le 03-03-2004 à 09:44:48    

Ah ces jeunes quel enthousiasme!! on jette tout et on recommence :-), ben non je n'ai pas vraiment le choix sauf celui de bidouiller et de coller des rustines...
 
Pour info il s'agit quand même d'une application critique qui tourne sur 20.000 PC animé ( si on peut dire...) de 386, 486 sous MSDOS 6.22 qui ne sont pas équipés de DD, donc tout doit tenir sur une (1!) disquette HD et dans les 640Ko de la mémoire basse... je vous rassure tout de suite c'est pas pour piloter des centrales nucléaires.  
 
 
Donc si tu as des info concernant le fonctionnement de l'allocateur de mémoire dans cet environnement ça m'intéresse toujours...  

Reply

Marsh Posté le 03-03-2004 à 11:11:20    

y'a pas 2 ou 4 mo de ram sur tes binious ?
 
j'ai pas dit on jette tout et on recommence, j'ai dit tu changes de compilo, 2/3 trucs à corriger, et t'as du code réutilisable pour plus tard...
 
après ça utilises le système graphique de borland ou c'est du mode texte ?


Message édité par bjone le 03-03-2004 à 11:15:18
Reply

Marsh Posté le 04-03-2004 à 10:13:40    

salut bjone,  
 
Oui, il y a au moins 2Mo de RAM, mais la mémoire dite haute est déjà utilisé comme ramdisk, il n'est pas envisageable de changer de compilo maintenant... oui, on utilise le système graphique de Borland ( BGI si je ne me trompe)...
 
La modif à l'aire de tenir si on tient encore 6 mois/ 1 an avec c'est bon, après on peut envisager de remplacer le soft et le hard...
 
 
 

Reply

Sujets relatifs:

Leave a Replay

Make sure you enter the(*)required information where indicate.HTML code is not allowed