Voila un avis que je partage parfaitement...Envoyé par davcha
Le pb c'est qu'en Java c'est GC obligatoire.
Ou alors on inclue des lib natives, mais ça pose beaucoup d'autres problèmes.
Voila un avis que je partage parfaitement...Envoyé par davcha
Le pb c'est qu'en Java c'est GC obligatoire.
Ou alors on inclue des lib natives, mais ça pose beaucoup d'autres problèmes.
Relis bien...dans un cas il copie, dans l'autre il pointe sur la tableau d'origine...Envoyé par adiGuba
Encore plus fun
T'inquiètes j'ai bien compris l'objectif des immuables, même si je n'adhère pas au concept.Envoyé par adiGuba
A toi de gérer au cas par cas...C'est vrai qu'on se pose souvent la question : valeur/référence...au débutEnvoyé par adiGuba
Exact...dommage qu'on ne puisse pas profiter du meilleur des deux mondes.Envoyé par adiGuba
Là, ça fait un bel argument en faveur du C#, par rapport à Java du coup.Envoyé par deneb
Et bien si le GC n'apporte rien au type de programme que tu fais, ne l'utilises pasEnvoyé par deneb
Tu ne vois pas l'interêt dans le cas d'une application client ?
Là ou les immuables sont pratiques c'est quand on souhaite passer un objet en paramètres à une fonction.Envoyé par deneb
Il arrive souvent qu'on ne puisse pas se permettre de lui passer son objet.
On peut passer une copie mais c'est couteux une instanciation, surtout dans une boucle !
Un objet immuable est parfait pour cela.
Et c'est comme ça que je les utilises.
Dans un langage qui ne supporte pas la const-correctness, les types immuables facilitent grandement la tâche en effet. Leur inconvénient, c'est que les types référence immuables nécessitent un GC pour être utilisables sans se prendre la tête avec les fuites.
Le GC peut être un avantage mais aussi un inconvénient ; la mémoire est fragmentée inutilement donc perte de performances possibles.Envoyé par deneb
C'est quelque chose que je ne savais pas; quel est l'intérêt de programmer avec un langage qui ne permet pas d'allouer + de 64Mo ?Envoyé par adiGuba
Comment tu fais si par exemple tu veux faire du traitement d'image sur des grosses images ?
Faut-il se cantonner aux API toutes faites du SDK de la JVM ( io.graphics ) ?
C'est certain que tout ce qui est architecture Java ou .NET cela demande plus de ressources matérielles donc crédits supplémentaires à allouer pour acheter des machines plus puissantes.Envoyé par deneb
Rien qu'à voir la taille du framework .NET....
C'est la valeur maximum par défaut ! Tu peux très simplement augmenter cette valeur avec l'option -Xmx de java lorsque tu lances ton application...Envoyé par mat.M
a++
ok merci du renseignement
Ils permettent aussi d'esquiver le Copy-On-Write (aka COW) si je ne m'abuse. Côté implémentaton, un pointeur intelligent à comptage de référence (que l'on doit pouvoir rendre atomiques) est très bien tant que tu n'as pas de cycles entre plusieurs objets non mutables.Envoyé par Médinoc
Mais, ne se retrouve-t-on pas à faire un fois deux à maintenir une version modifiable et une non-modifiable ?
C'est vrai qu'on voit rarement une classe String sans la classe StringBuffer(java) ou StringBuilder(.Net) qui va avec. Il est clair que le second inconvénient des types immuables est qu'il faut en créer un nouveau à chaque modification, et une allocation mémoire, c'est pas trop ce qu'il y a de plus rapide...
C'est pourquoi il y a les classes StringBuffer et StringBuilder (au passage : les deux existent sous Java 5.0 - l'une étant thread-safe ). Si tu dois faire plusieurs modifications sur une String, cela permet d'éviter d'effectuer plusieurs allocations...Envoyé par Médinoc
En même temps, je pense qu'il est quand même préférable de ne faire une allocation qu'à chaque modification, plutôt que pour chaque utilisation.
Prenons le cas d'une String qui sera utilisé dans 5 classes, dont une utilisera une version modifié (on dira en minuscule).
Avec un GC et le pattern immuable : tu n'auras alloué que 2 instances de String (voir une seule si la String est déjà en minuscule).
Sans GC et avec des classes muables, tu devras allouer une instance par classe, pour éviter les modifications depuis l'extérieur. Tu auras donc 5 allocations au minimum...
La plupart des problèmes avec le GC viennent de méconnaissance de son principe, et de la notion d'immuabilité...
L'exemple le plus frappant est l'utilisation de l'opérateur + sur les chaines, qui crée une nouvelle instance de String, et qui peut être catastrophique s'il est utilisé dans une boucle. Exemple avec le code suivant :
Qui donne une grosse différence comme résultat :
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
19
20
21 int max = 50000; long t0,t1; t0 = System.currentTimeMillis(); String string1 = ""; for (int i=0; i<max; i++) { string1 += "a"; } t1 = System.currentTimeMillis(); System.out.println("String1 : " + string1.length() + " caractères en " + (t1-t0) + " ms..."); t0 = System.currentTimeMillis(); StringBuffer buffer = new StringBuffer(); for (int i=0; i<max; i++) { buffer.append("a"); } String string2 = buffer.toString(); t1 = System.currentTimeMillis(); System.out.println("String1 : " + string2.length() + " caractères en " + (t1-t0) + " ms...");
Puisque dans le premier cas le GC alloue un grand nombre d'objet temporaire de manière implicite...
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2 String1 : 50000 caractères en 18312 ms... String2 : 50000 caractères en 16 ms...
En effet pour créer une chaine de 50000 char (soit 100Ko en mémoire puisque les char en java sont sur 2 octets), le GC aura en fait allouer plus d'1 milliard de char, soit plus de 2Go de mémoire...
Ca fait mal
Sans GC ni const-correctness... C'est pourquoi en C++, avec des std::string parfaitement modifiables, on arrive à n'allouer que deux strings également (mais c'est un poil plus long, car il faut d'abord copier la string et modifier la copie : En java, on peut faire la modification à la volée lors de la copie).Sans GC et avec des classes muables, tu devras allouer une instance par classe, pour éviter les modifications depuis l'extérieur. Tu auras donc 5 allocations au minimum...
Pour le reste, je suis d'accord.
Pas tout à fait : le const-correctness est très bien pour passer des paramètres à une méthode sans qu'il ne soit modifié et sans devoir en créer une nouvelle instance...Envoyé par Médinoc
Mais s'il s'agit d'attribut de classe, il faut alors en faire une copie pour éviter que l'attribut ne soit modifier en dehors de la classe, par exemple avec le code C++ suivant :
Si on ne copie pas id dans son contructeur de MyClass, on modifie sa valeur sans utiliser d'accesseur et on peut casser l'intégrité de l'objet... donc const ne sert à rien dans ce cas.
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3 std::string id = "azerty"; MyClass instance(id); std::transform( id.begin(), id.end(), id.begin(), toupper );
Maintenant, je ne pense pas qu'il y ai de grosse différence entre les deux, et que cela ne doti se voir que dans les cas extrêmes. Toutefois le GC facilite grandement les choses...
a++
Je n'ai pas testé, mais je vois une faille d'ici : Si tu as une référence const vers l'objet (ou un objet const), id.begin() te renverra un const_iterator, donc std::transform ne pourra pas modifier la chaîne...
Si j'avais déclaré ceci oui :Envoyé par Médinoc
Mais pas si le const est utilisé dans le paramètre du constructeur seulement :
Code : Sélectionner tout - Visualiser dans une fenêtre à part const std:string id = "azerty";
id ne pourrait pas être modifié à l'intérieur de la classe MyClass, mais cela reste possible en dehors de la classe, d'où le problème...
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3 MyClass::MyClass (const std::string& id) { ... }
a++
PS : en même temps mes souvenirs de C++ ne sont plus très bon donc je peux très bien me tromper...
Ah pardon, c'est moi qui n'avais pas compris ton précédent post
Oui, pour ce genre de choses, l'objet a tout intéret à contenir une copie.
Ok sur le coup tu m'a un peu mis le doute quand mêmeEnvoyé par Médinoc
De ce point de vue là on a deux philosophies différentes :Envoyé par Médinoc
a++
- Sans GC on fait des copies préventives.
- Avec un GC ET des classes immuables, on ne fait la copie que lorsque c'est néccessaire.
Ce que tu appelles pattern immuable est parfaitement applicable sans GC. Un simple comptage de références suffit.Envoyé par adiGuba
C'est donc pour ça que j'avais des codes C++ illisibles truffés d'append()... Des codeurs étaient passés par la case java.Envoyé par adiGuba
À peu près 70% de mes chaines, et 85% de mes autres données vivant sur la pile sont déclarées const. C'est sûr, c'est un peu plus long à écrire. Mais cela apporte d'autres avantages en termes d'expressivité.Envoyé par adiGuba
(Tiens, j'ai lu ça il n'y a pas longtemps)Envoyé par adiGuba
C'est un faux problème. D'abord, il n'intervient que dans deux cas et si on oublie un détail important.
- si on est dans un environnement thréadé et que le paramètre réel peut évoluer dans un autre thread -- si on se fait piéger par ça, alors l'appli a très certainement des problèmes plus sérieux de la famille des lecteurs/écrivains
- si on stocke une référence sur ce qui arrive depuis le constructeur d'un objet qui va vivre plus longtemps que la chaîne reçue.
- quand on oublie que les chaines ont avant tout une sémantique de valeur en C++
Le GC est ici un détail d'implémentation. Les classes immuables dont tu parles non besoin que d'une seule chose : un moyen de partager la zone mémoire où sont stockées les données (caractères pour les chaînes). Je vois au moins trois moyens d'y parvenir :Avec un GC ET des classes immuables, on ne fait la copie que lorsque c'est néccessaire.
- GC, certes
- comptage de références
- zone mémoire qui a une durée de vie bien plus importante que les données "immuables". Une implémentation typique qui est vieille au moins comme le C, ce sont les chaînes constantes litérales.
Rapidement, quelques mauvais souvenirs de C++ :
- mauvaise allocation : taille d'un objet dépassant sa taille allouée. Conséquence : l'objet débordait sur un autre pour fonctionner. Du coup l'objet en partie écrasée ne fonctionnait plus bien. On a cherché pendant des heures ce qui n'allait pas dans notre code sur ce sacré objet (une simple boîte aux lettres) avant de comprendre. Erreur que je préfère éviter à l'avenir !
- pile augmentant sans cesse, tuant toute mon appli et pénalisant sacrément mon OS..
Ce ne fut que sur des programmes simples... Je ne parle pas du dépassement de pile, qui certes ne m'est jamais arrivé mais m'a l'air fort fréquent et porte ouverte à bien des attaques...
Mauvais souvenirs en Java :
- taille de la heap trop faible. Conséquent : des erreurs "OutOfMemory" (facile à capter non ?). Correction : augmenter la heap et basta.
Maintenant c'est clairement une simple expérience, mais bon...
Par ailleurs, si on parle beaucoup des inconvénients du GC, on ne parle pas assez de ces avantages, qui sont notamment une gestion optimisée de la mémoire permettant des gains notables, et ce en 2 temps : lors de la compilation, les objets peuvent être réorganisés pour de meilleures perfs, lors de l'éxécution au lieu de bosser au niveau "unitaire" d'un objet le GC peut bosser avec des blocs d'objets, ce qui est bien plus rapide.
Au final, perso, je ne suis pas développeur "expert" et pourtant je fais du dev. Autour de moi, il y a bien un expert (et encore, il est plus architecte), mais sinon il n'y a que des jeunes développeurs (donc non experts). Du coup je pense qu'un GC a toute sa place : on limite vachement les risques en perdant très peu (voir rien : temps de dév plus cours, pas de prise de tête...). Et c'est d'un intérêt certain dans un programme professionnel.
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