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

  FORUM HardWare.fr
  Programmation
  C#/.NET managed

  [C Sharp/Résolu] mémoire et sauts pointeurs: la chasse au gaspi

 


 Mot :   Pseudo :  
 
Bas de page
Auteur Sujet :

[C Sharp/Résolu] mémoire et sauts pointeurs: la chasse au gaspi

n°1432094
nargy
Posté le 27-08-2006 à 13:48:38  profilanswer
 

Salut à tous :)
 
Celà fait plusieurs fois que je soupçonne avoir le même problème: j'ai un tableau de petits objets. Ces petits objets possèdent 2 ou 3 propriétés.
J'ai besoin de mettre ces objets dans un tableau.
 
Pour exemple, le dernier algo est un algo de plus court chemin où j'ai une classe:

Code :
  1. class RelaxPCC {
  2. public double poids;
  3. public int predecesseur;
  4. }


Ici <<poids>> représente le poids d'un arc dans un graphe, et <<predecesseur>> est le numéro du sommet précédant sur un plus court chemin.
 
Tous les sommets sont stockés dans une array: RelaxPCC[] sommets; et l'algorithme parcours plusieurs fois cette array pour trouver les plus courts chemins. (algo de Dijkstra)
 
Il me semble que l'array contient des pointeurs (en interne) vers les objets RelaxPCC, ce qui fait que pour accéder au poids par exemple, je me retrouve avec 2 sauts de pointeurs: trouver le pointeur vers l'objet numéro N (premier saut), puis trouver l'adresse où est stocké le poids (deuxième saut).
 
Outre un problème de rapidité sur de très gros graphes, il y a celui de la consommation mémoire: il y a une batterie de pointeurs en trop qui dans ce cas augmentent l'utilisation de mémoire d'1/3 (32+64 bits pour RelaxPPC+ 32bits par pointeur dans l'array). Tout celà ne fait que ralentir encore plus car encombre inutilement le cache CPU. Il me semble que d'utiliser deux arrays (une pour les poids, une pour les prédecesseurs) ne fait qu'empirer.
 
Or il y a plus simple: stocker directement dans l'array (à la C++) alternativement un double et un int avec dans ce cas 1 seul saut de pointeur pour récupérer le poids et une économie d'1/4 de mémoire.
 
Me trompe-je sur la gestion des objets en C Sharp?
Est-ce possible de réduire le nombre de déréférencements?
Est-ce possible de gagner en consommation mémoire?


Message édité par nargy le 29-08-2006 à 21:22:24
mood
Publicité
Posté le 27-08-2006 à 13:48:38  profilanswer
 

n°1432106
el muchach​o
Comfortably Numb
Posté le 27-08-2006 à 14:05:44  profilanswer
 

Vu que c'est une structure, je doute fortement qu'il y ait un pointeur pour accéder aux membres. La taille des membres est connue par le compilo, donc il n'a pas besoin d'un pointeur supplémentaire. Donc en mémoire, l'organisation est déjà telle que tu la décris: un double et un int alternativement (parfois, il peut y avoir du padding pour l'alignement).
C'est en tout cas comme ça avec un compilo C++ et je ne vois pas bien pourquoi ce serait différent en C# ou en Java sur ce point.
 
Si tu veux en être sûr, il faut lire la spec du langage.
Ce qui m'étonne par contre, c'est le fait de représenter un graphe par un tableau.


Message édité par el muchacho le 27-08-2006 à 14:09:37

---------------
Les aéroports où il fait bon attendre, voila un topic qu'il est bien
n°1432112
nargy
Posté le 27-08-2006 à 14:26:30  profilanswer
 

Ha oui, exact, les lenteurs viennent d'une ArrayList.
Que vais donc changer en array.
 
Si, il s'agit de l'algo de Dijkstra, qui parcours les sommets séquentiellements par adjacence, jusqu'à découvrir petit à petit tous les sommets, et qui place dans une ArrayList les sommets pour lesquels aucun plus court chemin n'est plus possible à trouver.
 
Maintenant que je me rappelle, j'avais aussi utilisé des ArrayList dans d'autres algos, donc à revoir aussi.
 
Pour la conso mémoire c'est à revoir aussi.
 
Merci pour tes éclaicissements, ceci dit comme je peux mettre un objet null dans une case d'une array, je me dit qu'il y a sûrement un pointeur quelquepart.

n°1432416
_Mose_
Lonesome coder
Posté le 28-08-2006 à 11:15:39  profilanswer
 

Petits éclaircissements à la lueurs de mon expérience (je n'ai pas la prétention d'un savoir absolu).
 
* En C# on parle de référence, et pas de pointeur.
Un pointeur tu peux le faire bouger dans ta mémoire (ce qui implique que tu connaisse l'organisation de la mémoire)
Une référence en .Net ça ne pointe que sur des objets d'un type bien définis, dans des zones mémoires dont l'organisation est complètement opaque.
 
* Les variables que contiennent ta structure ne sont pas des références. Quand tu les instancies, tu ne fais pas "new", ce sont des types primitifs. Quand tu fais int a = 5; int b = 5; a++;, tu sais que le a++ ne modifie pas la valeur de b. Ils sont bêtement recopiés par l'opérateur "=", et donc directement contenus dans ta structure.
 
* Niveau mémoire, je te conseille de faire des tests avec une structure et avec une classe. Tu penses sans doute qu'une classe c'est plus lourd. Oui, c'est vrai dans l'absolu d'une implémentation C++, mais l'implémentation de .Net est différente. Je n'ai pas de site qui l'explique bien, mais quand tu instancies deux objets A et B de la même classe, en mémoire, tout la classe n'est pas recréée en mémoire. Seule ses parties modifiables (champs/évènements) sont multiples. La partie commune (définitions des méthodes/propriétés) n'est créée qu'une seule fois. Pour les structures, le fonctionnement est différent. Désolé de ne pas pouvoir t'en dire plus, mais c'est l'avantage et l'inconvénient des langages de haut niveau comme .Net et Java : ne pas s'intéresser à ce qui se passe en dessous.
 
* Pour les ArrayList : oui, t'as complètement raison, c'est clairement à éviter quand tu veux des bonnes perfs sur des tableaux assez gros. Si tu as une idée de la volumétrie, tu pourrais faire un tableau statique de noeuds plutôt qu'un tableau dynamique. (ou 'n' tableaux statiques)
 
* Sinon ta solution d'utiliser deux tableaux d'info sur tes noeuds au lieux d'un tableau de noeuds, bah à la limite pourquoi pas. C'est l'avantage de l'objet : tu peux faire deux implémentations différente et garder le même code au niveau supérieur. Si tu essayes, partage tes résultats. Ca m'intéresse.

n°1432558
nargy
Posté le 28-08-2006 à 15:10:09  profilanswer
 

Donc, après quelques tests, la bonne solution est d'utiliser une struct et non une class. Dans ce cas il n'est plus possible de mettre null dans une case de tableau. De même un tableau d'int ne peut en fait contenir null.
 
Quand à arraylist... elle convertit la struct (type valeur) en object (type nullable). On se retrouve donc encore avec des pointeurs.
 
Je parle de pointeurs puisque en principe une référence ne peut être nulle. C'est un pointeur bridé car en effet l'arithmétique de pointeurs n'est pas disponible.

n°1433403
nargy
Posté le 29-08-2006 à 21:21:53  profilanswer
 

Ok: la théorie rejoint la pratique; c'est à vue d'oeil plus rapide.
Résolu.

n°1439574
Tamahome
⭐⭐⭐⭐⭐
Posté le 09-09-2006 à 20:15:25  profilanswer
 

pourquoi n'utilises tu pas les Generics ? un petit List<RelaxPCC> et ca devrait faire l'affaire :D


---------------
Hobby eien /人◕ ‿‿ ◕人\
n°1439579
nargy
Posté le 09-09-2006 à 20:58:37  profilanswer
 

Heu... ben non. Je connais par avance le nombre de noeuds du graphe, donc je peux allouer un tableau statique. Si j'utilise une liste (enfin je suppose que List<> représente une liste simplement ou doublement chaînée -- j'ai pas de compilo sous la main pour vérifier en ce moment) j'ai 1 ou 2 pointeurs de plus par noeud.
 
Pour ceux que ça interesse, j'ai fait quelques expériences avec les ArrayList, ce n'est pas comme leur nom laisserait penser une liste de tableaux, mais ce qu'on appelle un tableau dynamique. C'est à dire que le tableau supporte l'opération Ajouter, en doublant si necessaire la taille du tableau interne et en recopiant les éléments déjà présents. On montre que cet algorithme utilise une taille mémoire au pire de O(2n) et l'opération Ajouter est en moyenne en O(3n).
 
Une autre solution, plus rapide avec presque la même quantité de mémoire, consiste à faire une liste chaînée simple de tableaux (et un pointeur sur le dernier tableau). Ces derniers sont alloués à chaque fois avec une taille double lorsque l'on doit ajouter un élément qui fait déborder. Lorsque l'on doit avoir accès à un élément par son index, la liste est recopiée dans un seul grand tableau de taille double (comme l'arraylist). Cette structure supporte aussi l'opération Vider (en O(log(n)) caché par le GC, qui supprime tous les éléments), et l'opération Economiser (en O(n) qui restreint la taille du tableau interne au nombre d'éléments). La conséquence étant qu'une série d'Ajouter puis un Economiser prends au total O(2n) opérations. Les autres opérations sont de même ordre de grandeur que celles d'une ArrayList, c'est à dire pas très interessantes. Je ne compte pas la mize à zéro (valeurs par défaut) des éléments d'un tableau CSharp, mais ça revient (à un facteur 2 près...) au même.

n°1439580
Harkonnen
Modérateur
Un modo pour les bannir tous
Posté le 09-09-2006 à 21:13:31  profilanswer
 

_Mose_ a écrit :


* Les variables que contiennent ta structure ne sont pas des références. Quand tu les instancies, tu ne fais pas "new", ce sont des types primitifs. Quand tu fais int a = 5; int b = 5; a++;, tu sais que le a++ ne modifie pas la valeur de b. Ils sont bêtement recopiés par l'opérateur "=", et donc directement contenus dans ta structure.


Il n'y a pas de types primitifs en C#. Les types "primitifs" (int, double,...) sont en fait des alias vers des objets de type System.Int32, System.Double, etc...
 
Sinon, nargy, pour ce genre de question, je te conseille fortement de regarder le source MSIL de tes programmes, c'est une mine d'or et on comprend beaucoup de choses en le parcourant (par exemple, on peut s'apercevoir que les delegates et les events sont exactement la même chose, sauf que les events n'exposent que 2 accesseurs : add et remove, correspondant respectivement aux opérateurs += et -=)


---------------
J'ai un string dans l'array (Paris Hilton)
n°1439582
Harkonnen
Modérateur
Un modo pour les bannir tous
Posté le 09-09-2006 à 21:20:14  profilanswer
 

Allez, pour illustrer, la preuve par MSIL que les types primitifs sont des alias. Une petite addition toute conne :

Code :
  1. namespace primitif
  2. {
  3.    class Program
  4.    {
  5.        static void Main(string[] args)
  6.        {
  7.            int a = 3;
  8.            int b = 12;
  9.            Console.WriteLine("a+b={0}", a + b);
  10.        }
  11.    }
  12. }


et le code MSIL correspondant :

Code :
  1. .method private hidebysig static void  Main(string[] args) cil managed
  2. {
  3.   .entrypoint
  4.   // Code size       26 (0x1a)
  5.   .maxstack  3
  6.   .locals init ([0] int32 a,
  7.            [1] int32 b)
  8.   IL_0000:  nop
  9.   IL_0001:  ldc.i4.3
  10.   IL_0002:  stloc.0
  11.   IL_0003:  ldc.i4.s   12
  12.   IL_0005:  stloc.1
  13.   IL_0006:  ldstr      "a+b={0}"
  14.   IL_000b:  ldloc.0
  15.   IL_000c:  ldloc.1
  16.   IL_000d:  add
  17.   IL_000e:  box        [mscorlib]System.Int32
  18.   IL_0013:  call       void [mscorlib]System.Console::WriteLine(string,
  19.                                                                 object)
  20.   IL_0018:  nop
  21.   IL_0019:  ret
  22. } // end of method Program::Main


Ligne 6 : On constate que les locales a et b sont en fait des Int32
Ligne 17 : Le résultat de l'addition est boxé en Int32
D'une limpidité sans faille. Je ne saurais que trop recommander de se mettre au MSIL, ça sert toujours.


Message édité par Harkonnen le 09-09-2006 à 21:32:45

---------------
J'ai un string dans l'array (Paris Hilton)
mood
Publicité
Posté le 09-09-2006 à 21:20:14  profilanswer
 

n°1439590
nargy
Posté le 09-09-2006 à 23:21:32  profilanswer
 

hmmm... le code est interessant en effet..
 
ceci dit, je ne l'analyse pas de cette façon, si le résultat de l'addition est boxé c'est parceque WriteLine prends des objets en paramètre (pointeurs/références vers les valeurs) et non des <<types-valeur>>.

n°1440395
_Mose_
Lonesome coder
Posté le 11-09-2006 à 15:42:34  profilanswer
 

Harkonnen a écrit :

Il n'y a pas de types primitifs en C#. Les types "primitifs" (int, double,...) sont en fait des alias vers des objets de type System.Int32, System.Double, etc...

Oui et non.
Oui, il aurait été plus exact de parler de types valeur (ValueType).
Non, ce ne sont pas des classes en interne. Ce sont bien des types 'primitifs' (y'a une meilleure traduction pour "built-in types" ?)
C'est le boxing qui donne l'illusion que ce sont des classes et permet de s'en servir comme tel.
+1 pour nargy.
http://msdn.microsoft.com/library/ [...] xingPG.asp


Aller à :
Ajouter une réponse
  FORUM HardWare.fr
  Programmation
  C#/.NET managed

  [C Sharp/Résolu] mémoire et sauts pointeurs: la chasse au gaspi

 

Sujets relatifs
Retourner à la boucle précédente [Résolu]alert c'est de la fouli avec GL&SDL[resolu]
[Résolu] [C#.Net] Ecrire dynamiquement le contenu d'un <legend>[RESOLU]newsletter - vérifier l'installation de Mysql [RESOLU]
[PHP ou JS]Protection de page (résolu)[Résolu] Connaitre le bouton appuyé lors d'un drag&drop?
[resolu]creer un site reserve a la famille[RESOLU] Afficher popup, variable php
Problème pour rendre une Winform invisible [Resolu][Résolu]Problème avec le chemin du fichier courant!
Plus de sujets relatifs à : [C Sharp/Résolu] mémoire et sauts pointeurs: la chasse au gaspi


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