pour avoir participé à de nombreux développements sur les technologies Java embarqué et temps réel, je peux t'assurer que Java peut largement fonctionner sur ce type de matériel, et pourrais même d'ailleurs beaucoup mieux fonctionner
pour avoir participé à de nombreux développements sur les technologies Java embarqué et temps réel, je peux t'assurer que Java peut largement fonctionner sur ce type de matériel, et pourrais même d'ailleurs beaucoup mieux fonctionner
Bonjour,
après lecture d'une grande partie d'une débat, j'ai envie de vous faire partager mon expérience. Je fais un jeu vidéo en Java, un gros jeu qui demande beaucoup de mémoire (350 Mo en gros, démo sur http://www.anadoncamille.com/).
Heureusement qu'il y a le Garbage Collector, cela m'épargne le fait d'écrire toutes les routines d'allocation et de désallocation. Certes on maîtrise moins finement la mémoire, mais vu le gain de temps au niveau codage brut, c'est une bonne affaire.
Je suis passé du C++ au Java et je suis resté au Java car les allocations de mémoire n'étaient pas ma partie préférée niveau programmation.
La présence du GC n'empêche pas de faire du code propre et des (dés)allocations mémoires adaptées. C'est à la responsabilité des développeurs.
J'ai un ami a qui on a offert une moto. Peu après il s'est plaint de rhumatismes parce qu'il ne marchait plus assez. Mais est-ce la faute à la moto si il choisit de ne plus faire sa marche quotidienne ?
Le Garbage Collector est une facilité de développement, mais demande la même rigueur dans la conception qu'un projet soutenu par une gestion de mémoire manuelle. Beaucoup critiquent le GC parce que son fonctionnement n'est pas à leur goût, mais il me semble qu'ils en rêvent, du GC qui est à leur goût.
-----
Pour ce qui est de réserver la mémoire au bon moment, c'est effectivement délicat. Avoir la mémoire est possible, à l'instant t c'est autre chose.
Mais on peut essayer ceci :
Dans un premier temps, être rigoureux quant au déréférencement, c'est le correspondant des freeMemory de C++. Ce n'est pas la même fonctionnnalité mais demande la même discipline.
Ensuite, au lancement de Java, on peut indiquer quelle quantité de mémoire on désire, avec les paramètres -Xms et -Xmx.
Muni de ces deux aspects, on veut de la mémoire à l'instant t. Déjà pour être sûr qu'elle est réellement disponible, il faut avoir été rigoureux et savoir ce qui est alloué et ce qui ne l'est pas. Puis, désallouer ce qui est inutile ou pourra être rechargé plus tard (images, musiques, sons), bref ne garder que l'indispensable.
Il faut avoir en tête la taille des données et les proportions. Il vaut mieux désallouer volontairement une seule image que 10000 String.
Après il faut attendre le travail du Garbage collector, éventuellement le solliciter jusqu'à être sûr d'avoir la quantité de mémoire voulue.
Quelques méthode utiles pour faire ce boulot, gérer plus finement la mémoire en coopération avec le GC :
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18 System.runFinalization(); // les objets déréférencés sont désalloués //==================== System.gc(); // appel volontaire du GC //==================== // Indique la mémoire allouée au programme (-Xms/-Xmx, en Mo) public static double getMemory() { return (double)Runtime.getRuntime().totalMemory() / (double)(1024 * 1024); } // Indique la mémoire actuellement disponible (en Mo) public static double getFreeMemory() { return (double)Runtime.getRuntime().freeMemory() / (double)(1024 * 1024); }
__________________________________
| +
| Sylvain Tournois - Création logicielle
|
| sylv.tournois.free.fr
|
Ceci est un soucis qui n'est pas exclusif à l'allocation avec un garbage collector, c'est un problème dès qu'il est question d'allocation dynamique. Dès qu'une allocation est lancée, toute une machinerie est mise en route :Il faut avoir en tête la taille des données et les proportions. Il vaut mieux désallouer volontairement une seule image que 10000 String.
Grosso modo :
- recherche d'espace dans les blocs disponibles
- si il n'y a plus de place, il faut effectuer des appels systèmes pour augmenter la taille du tas
- choisir effectivement une zone mémoire (qui est plus importante que la taille effectivement demandée)
- référencer la zone prise quelque part (soit avec une table de hachage, soit avec une liste chainée, soit avec autre chose)
Il y a plusieurs techniques pour choisir les blocs, mais ça sera pour une autre fois.
Donc, faire 10.000 allocations d'entier prendra énormément plus de temps et de place que faire l'allocation d'un tableau de 10.000 entier (sauf cas particulier de redéfinition des opérateurs new et delete).
De plus, la fragmentation sera plus importante dans le premier cas si l'on ne désalloue pas tout d'un coup.
Je ne répondrai à aucune question technique en privé
J'ai eu à rechercher les origines d'une augmentation continuelle de l'occupation mémoire dans un programme Java écrit par d'autres. Il me semble que contrairement à ce qui c'est dit ici le Garbage Collector ne libère pas les objets qui se référencent mutuellement et qui ne sont pas référencés par ailleurs.
Voici un petit test qui met en évidence que le garbage collector ne libère pas les objets qui se réfèrent l'un l'autre même dans des situation simples à détecter.
Code Java : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 public class TestGc { byte[] b = new byte[100000]; TestGc ref = new TestGc(); public static void main(String[] args) { int nb = 1000; for (int i=0; i < nb; i++){ new TestGc(); System.gc(); } System.out.println("c'est fini"); } }
Excécutez ce code et vous allez obtenir une exception "out of memory".
Supprimez la ligne "TestGc ref = new TestGc();" et vous n'aurez plus d'exception même si vous augmentez la valeur de "nb".
Je m'apperçois que mon test précédent était erronné : je créais des objets en cascade illimité et il était donc normal que j'obtienne un "out of memory".
J'ai fait un autre test (plus correct) et il semblerait qu'ici le garbage collector joue bien son rôle :
Code Java : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 public class TestGc { byte[] b = new byte[100000]; TestGc ref; public TestGc(TestGc t){ this.ref = t; } public static void main(String[] args) { int nb = 2000; TestGc t=null; for (int i=0; i < nb; i++){ t = new TestGc(t); if (i%5 == 0) t = null; System.gc(); } System.out.println("c'est fini"); } }
Je crée ici des morceux de listes chainées avec des ruptures, GC libère bien la mémoire.
A l'occasion, je vais tenter de trouver des situations plus complexes où GC serait défaillant. Je vous tiendrai au courant.
Systèmes d'Informations Géographiques
- Projets : Unlicense.science - Apache.SIS
Pour un monde sans BigBrother IxQuick ni censure RSF et Les moutons
tout dépend de ta définition de très bien.
n'oublies pas que le mieux est l'ennemi du bien... (et il est clair que depuis jdk 1.4 c'est mieux côté GC )
si l'on devait à d'autres systèmes de GC, je pense que celle de Java est assez moyenne... mais certainement suffisante dans 80% des cas
j'irai meme jusqu'a 95%, je fais des applis plutot poussé en demande memoire avec la cartographie, quelques centaines de milliers de ligne d'une base spatiale a afficher et des images raster pouvant aller a 8000*8000 pixels. bref ca passe de quelques Mo a plus de 400 en peu de temps, et ca redescend a quelque Mo une fois les données retirées.
Et puis on peu jouer avec different niveau de reference en java.
Hardreference, WeakReference, SoftReference et PhantomReference pour differente facon de gerer sa memoire.
Systèmes d'Informations Géographiques
- Projets : Unlicense.science - Apache.SIS
Pour un monde sans BigBrother IxQuick ni censure RSF et Les moutons
La question "pour ou contre le GC" est peut-être dépassée, si on considère que même le C++, pourtant utilisé dans des cas extrêmes de programmation à haute performance, a bien failli avoir un GC en standard dès l'année prochaine. Apparemment en Novembre ça a été remis à un TR pour peut-être 2010, mais c'est dans le tube. Par ailleurs, le monde du C++ est maintenant habitué à la gestion automatique de la mémoire, que ce soit par l'intermédiaire de la librairie standard, par les toutes les librairies utilisant maintenant systématiquement au moins les compteurs de référence, par les implémentations commerciales, et par des variantes à GC très agressif comme C++/CLI, massivement utilisé en environnement Windows.
Donc il ne fait pas de doute maintenant que la présence d'un GC est considéré par les concepteurs de langage comme une composante obligatoire d'un langage moderne.
La question est plutôt: quand ne pas l'utiliser? Ou encore: faut-il même laisser la possibilité à l'utilisateur de ne pas l'utiliser? Les avis sont là peut-être plus partagés.
En ce qui me concerne, je suis totalement pour la présence d'un GC obligatoire en standard, désactivable seulement par option de compilation. Dans certains environnements, je pense en effet qu'il est préférable de ne pas faire confiance aux programmeurs pour qu'ils utilisent proprement les différents "smart pointers" proposés jusqu'ici par C++.
"Maybe C++0x will inspire people to write tutorials emphasizing simple use, rather than just papers showing off cleverness." - Bjarne Stroustrup
"Modern C++11 is not your daddy’s C++" - Herb Sutter
Bonjour à tous,
A l'instar de ac_wingless, je suis d'avis qu'un GC devrait être la norme et non l'exception.
En effet, si me m'en réfère à ma propre expérience, les problème lié à la gestion de pointeurs partagés dans des applications complexes surpasse largement les désavantage potentiel d'un GC. Je ne dis pas qu'il n'y a pas de problème avec GC, ni qu'il est sage d'ignoré le fonctionnement du GC qu'on utilise, mais à quoi bon vouloir à tout prix s'en passé si c'est pour finir dans bien des cas, avec un ersatz de GC avec une foule de limitation et de la complexité supplémentaire et du code à maintenir.
Dans l'industrie de l'aviation, pas question de GC ni même d'allocation dynamique de mémoire tout court... c'est comme ça, y a pas à discuter. C'est probablement comme ça également pour le logiciel embarqué dans les appareils médicaux ou gestion de centrales nucléaires... mais quand il s'agit d'applications complexes où l'éventualité d'un manque de mémoire ou d'un plantage n'est pas un danger mortel, je ne vois pas plus raison de se passer d'un GC que de la programmer en assembleur.
Voilà pour mon humble avis.
Meilleures salutations,
Jérôme
Bonjour,
Sun veut pousser un nouvel algo dans la prochaine jvm java.
Cet algo permettra de se rapprocher des contraintes du temps reels on offrant l'assurance de ne pas bloquer l'application plus qu'un contrat prédéfinie.
J'ai écris un billet à ce sujet il y a quelque temps sur le blog de Xebia, celui-ci compare le fonctionnement d'un GC générationnel tel qu'il est actuellement utilisé sur les jvm Sun avec le nouvel algo.
http://blog.xebia.fr/2008/03/12/gc-g...ge-first-jdk7/
Di'ici à faire rentrer cette forme de jvm dans l'aviation, il y a encore du travail ...
Réchauffons ce vieux débats :-)
Ce qui me frappe chez les détracteurs de la notion de Glaneur de Cellules, en particulier deneb, c'est qu'ils se placent dans une situation où la gestion manuelles de la mémoire est possible, et ils disent "regardez, là, je peux gérer ma mémoire à la main". Ce qui, je trouve, n'a pas été assez souligné est que dès que la mémoire peut être géré à la main, elle peut l'être géré par un GC, alors que l'inverse n'est pas vrai ! Le problème de la gestion manuelle de la mémoire, c'est qu'il faut savoir à l'avance quand un objet sera libérable, et ce n'est généralement pas possible (pour ce qui est des magic pointers et autre compteur de références, ce ne sont jamais que des formes faibles et non fiable de GC, donc autant en utiliser un vrai, un qui résiste aux structures cyclique)
deneb nous dit qu'il "suffit" de se contraindre au patern "celui qui alloue libère." Mais existe-t-il la moindre raison valable de se plier à cette discipline en dehors justement de la gestion manuelle de la mémoire ?
Il me semble au contraire qu'il y a plein de bonne raison de ne pas le faire. Dès que l'on désire avoir des structures persistantes par exemple. Et je ne parle pas simplement de l'optimisation d'avoir une String non mutable...
Supposons que j'ai des ensembles de chaines de caractère, codés par des arbres (à la Set dans OCaml pour ceux qui connaissent). Quand j'ajoute une nouvelle chaine, ça ne modifie pas mon ensemble, ça m'en retourne un nouveau, modifié, et l'ancien reste disponible inchangé. Mais évidement, l'implémentation n'est pas naïve et ne recopie pas l'arbre ! Il y a partage de la majorité des branches.
On peut imaginer plein d'utilisation de ce genre de chose. Par exemple, je construis une fois pour toute l'arbre avec l'ensemble des mots de la langue française, et j'ajoute parfois les mots technique informatique, et une autre fois les mots d'argots.
Et quand j'en ai fini avec ma version technique, est ce que je peux m'en débarasser ? Bien sûr que non, puisque la version argotique partage de nombreux mots.
Est ce que la fonction d'ajout d'un mot dans la structure peux savoir quand désallouer ? Évidement non.
Il ne reste plus que la solution GC.
Pour résumer, outre le fait qu'on perd énormément de temps à gérer sa mémoire à la main, avec un risque d'erreur bien plus important (et non, une double désallocation n'entraine malheureusement pas toujours un crash direct..), s'imposer cette forme de gestion limite tout simplement les possibilité de ce qu'il est possible de faire ! Après, je ne dénigre pas le fait que dans certain cas très spécifique, une gestion manuelle de la mémoire peut être indispensable.
Ensuite à la question "pourquoi ne peut-on pas désallouer à la main quand ça nous chante", la réponse est "parce que sinon ça casse tout" ! Si j'ai deux variable a et b qui référencent le même objet, que je le déréférence via a (qui peut alors éventuellement basculer sur null), je fais quoi de b ? Si quelqu'un y accède, c'est le drame. Et dire "le programmeur n'a qu'à faire gaffe", c'est contraire au principe de Java et justement de son modèle de gestion de la mémoire qui est d'apporter une forme de sécurité.
Voilà, j'ai apporté mon petit caillou au tas de pierre :-)
Comptes-tu la solution "comptage de références" comme incluse dans la solution "GC" ?
SVP, pas de questions techniques par MP. Surtout si je ne vous ai jamais parlé avant.
"Aw, come on, who would be so stupid as to insert a cast to make an error go away without actually fixing the error?"
Apparently everyone. -- Raymond Chen.
Traduction obligatoire: "Oh, voyons, qui serait assez stupide pour mettre un cast pour faire disparaitre un message d'erreur sans vraiment corriger l'erreur?" - Apparemment, tout le monde. -- Raymond Chen.
En C++ avec les bons pointeurs intelligents, on peut la rendre implicite facilement.
Et pour des types "feuilles" comme les chaînes de carcatères, les risques de cycles sont nuls.
SVP, pas de questions techniques par MP. Surtout si je ne vous ai jamais parlé avant.
"Aw, come on, who would be so stupid as to insert a cast to make an error go away without actually fixing the error?"
Apparently everyone. -- Raymond Chen.
Traduction obligatoire: "Oh, voyons, qui serait assez stupide pour mettre un cast pour faire disparaitre un message d'erreur sans vraiment corriger l'erreur?" - Apparemment, tout le monde. -- Raymond Chen.
Compare avec http://en.wikipedia.org/wiki/Garbage...puter_science) et après on reparle du comptage de référence comme GC ?
Tu peux aussi chercher pour generational garbage collector pour avoir un ordre d'idée sur ce qu'est un GC moderne.
Les pointeurs sont intelligents n'ont de lourd que les noms de types à rallonge -- du moins en C++ tant que l'on ne passe pas par des typedef.
En revanche, ils ont une chose que ne possèdent pas les GCs : le déterminisme. Sur la mémoire, c'est sûr qu'une approche non déterministe peut s'avérer plus efficace, et sans mise en danger du système. Cependant, sur les autres ressources la différence est critique.
En cela, la solution de C# est intéressante : ce langage différencie la mémoire qui est collectée quand bon lui semble et les ressources pour lesquelles on peut disposer d'une finalisation déterminisme et pseudo-implicite (avec using) -- en Java, on passe à l'explicite lourd (try-finalize); OCaml, je ne connais pas.
Quant aux cycles ... ma foi, pour l'instant ils ne me gênent pas. Et combien même en réfléchissant un minimum, on voit vite où mettre du shared_ptr<>, et où mettre du weak_ptr<>
Blog|FAQ C++|FAQ fclc++|FAQ Comeau|FAQ C++lite|FAQ BS|Bons livres sur le C++
Les MP ne sont pas une hotline. Je ne réponds à aucune question technique par le biais de ce média. Et de toutes façons, ma BAL sur dvpz est pleine...
Je n'ai jamais parlé du comptage de réference "comme GC", mais comme aide à la gestion de mémoire. Je trouve le comptage de références particulièrement adapté aux types simples (chaînes) et aux conteneurs...
SVP, pas de questions techniques par MP. Surtout si je ne vous ai jamais parlé avant.
"Aw, come on, who would be so stupid as to insert a cast to make an error go away without actually fixing the error?"
Apparently everyone. -- Raymond Chen.
Traduction obligatoire: "Oh, voyons, qui serait assez stupide pour mettre un cast pour faire disparaitre un message d'erreur sans vraiment corriger l'erreur?" - Apparemment, tout le monde. -- Raymond Chen.
Vous avez un bloqueur de publicités installé.
Le Club Developpez.com n'affiche que des publicités IT, discrètes et non intrusives.
Afin que nous puissions continuer à vous fournir gratuitement du contenu de qualité, merci de nous soutenir en désactivant votre bloqueur de publicités sur Developpez.com.
Partager