'jour, 'nal,
On va manipuler la mémoire native sans devoir utiliser des pointeurs, donc en continuant de profiter de la sécurité mémoire garantie par le GC.
Eh oui, on va avoir notre gâteau et le manger en même temps. Nananère !
En effet, beaucoup d'bêtises imprécisions ont été écrites sur les langages à GC et leurs performances.
Or, cet excellent article remet les pendules à l'heure.
Les liens de base pour éviter d'écrire des bêtises dans les commentaires :
- Principes de base du GC
- Garbage collection and Performance
- Les bases du CLR (la VM) Gestion de la mémoire et garbage collection (GC) dans ASP.NET Core
- Réutilisation des objets avec ObjectPool dans ASP.NET Core
Et ceux pour aller plus loin :
- Span (ou via une vidéo rigolote)
- fixed (conversion d'une variable en pointeur)
- stackalloc
- Memory MemoryHandle
- NativeMemory
- Managed Threading Best Practices
# fish and chips
Posté par Arvil . Évalué à 3.
On est déjà Vendredi ? Il est où l'argument ?
[^] # Re: fish and chips
Posté par xcomcmdr . Évalué à 1.
L'argument est qu'il n'y a pas à utiliser des langages natifs (tels que le C), avec tout ce que cela implique comme risque, au moindre souci de performance. Juste sa tête.
Ou au pire (je dis bien au pire) des Span et autres ArrayPool (chose qui ne sera jamais utilisée par 99,9 pourcent des développeurs en quête de performance).
"Quand certains râlent contre systemd, d'autres s'attaquent aux vrais problèmes." (merci Sinma !)
[^] # Re: fish and chips
Posté par gUI (Mastodon) . Évalué à 8.
Si tu es capable d'utiliser ta tête, alors utilise le C.
En théorie, la théorie et la pratique c'est pareil. En pratique c'est pas vrai.
[^] # Re: fish and chips
Posté par xcomcmdr . Évalué à -2.
Si tu es capable d'utiliser ta tête, utilise l'assembleur.
"Quand certains râlent contre systemd, d'autres s'attaquent aux vrais problèmes." (merci Sinma !)
[^] # Re: fish and chips
Posté par gUI (Mastodon) . Évalué à 6.
Si tu ne sais pas la différence fondamentale entre C et assembleur, continue à faire du Java alors.
En théorie, la théorie et la pratique c'est pareil. En pratique c'est pas vrai.
[^] # Re: fish and chips
Posté par xcomcmdr . Évalué à -5.
Si tu ne sais pas la différence fondamentale entre trolle et argumenter, continue de confondre Java et C# alors.
"Quand certains râlent contre systemd, d'autres s'attaquent aux vrais problèmes." (merci Sinma !)
[^] # Re: fish and chips
Posté par gUI (Mastodon) . Évalué à 3. Dernière modification le 18 septembre 2022 à 13:50.
Je te trouve bien chafouin pour un troller… (PS : ça se voit que c'est toi que me mets -1 il y a des techniques pour faire ça plus discrètement)
En théorie, la théorie et la pratique c'est pareil. En pratique c'est pas vrai.
[^] # Re: fish and chips
Posté par xcomcmdr . Évalué à -2.
Rohhh tout de suite on m'accuse.
J'ai rippé. Trois fois. Ça arrive à tout le monde.
"Quand certains râlent contre systemd, d'autres s'attaquent aux vrais problèmes." (merci Sinma !)
[^] # Re: fish and chips
Posté par tisaac (Mastodon) . Évalué à 8.
Un barbu, c'est un barbu…Trois barbus, c'est des barbouzes !
Surtout, ne pas tout prendre au sérieux !
[^] # Re: fish and chips
Posté par YBoy360 (site web personnel) . Évalué à 5.
D'autant plus qu'il y a des combo-multiples dans l'article en lien (bien que ce soit intéressant) :
Bref, dommage qu'on ne soit pas vendredi, en effet… Si quelqu'un veut profiler tout ça pour la lecture du soir, ce serait sympa.
[^] # Re: fish and chips
Posté par Olivier Abad . Évalué à 2.
Il met les accolades au bon endroit pour rendre son code lisible.
Ce sont tous les autres qui les mettent au mauvais endroit (moi compris car je travaille avec des gens qui les mettent au mauvais endroit, et donc je fais comme eux) !
[^] # Re: fish and chips
Posté par windu.2b . Évalué à 6.
"Je mets les accolades où je veux, Little John, et c'est souvent dans la gu…"
Pardon : je me suis trompé de citation ;-)
# Mes impressions
Posté par Christophe . Évalué à 10.
Très franchement, en lisant l'article, je ne sais pas vraiment quoi en déduire. En tout cas, je ne suis pas convaincu.
En effet, le code optimisé est très efficace, mais :
On passe d'un code lisible (je comprends bien ce qu'il fait, sans connaître C#) à un code dont la fonction de base est noyée dans les optimisations
Le résultat est rapide, principalement parce que… le GC n'a plus rien à faire. On précalcule, on réutilise des buffers, etc. Donc OK, le code est rapide, mais on peut très bien en conclure l'opposé de ce que tu sembles indiquer: dans ce langage avec GC, une façon d'obtenir de bons résultats est d'éviter ce boulet de GC.
[^] # Re: Mes impressions
Posté par xcomcmdr . Évalué à -2.
Tout à fait, et ce sans devoir faire du C.
Et on peut pas dire que le GC est imprévisible, ni que les solutions sont manquantes. Non, c'est le dev qui est incompétent, nuance.
Le code de l'article va de plus en plus loin, mais même la première étape (utiliser les Span) est rarement justifié.
Quand tu as une bonne vieille GC storm tu faisais déjà nawak niveau allocations et le GC n'est que le messager. il suffit de les revoir un brin. Tu sortira jamais un Span.
"Quand certains râlent contre systemd, d'autres s'attaquent aux vrais problèmes." (merci Sinma !)
[^] # Re: Mes impressions
Posté par gUI (Mastodon) . Évalué à 2.
Quand le dev est compétant, il code en C.
Oui, je me répète, mais c'est toi qui a commence à troller :)
En théorie, la théorie et la pratique c'est pareil. En pratique c'est pas vrai.
[^] # Re: Mes impressions
Posté par xcomcmdr . Évalué à -7.
Quand le dev est compétent, il code directement en code machine.
"Quand certains râlent contre systemd, d'autres s'attaquent aux vrais problèmes." (merci Sinma !)
[^] # Re: Mes impressions
Posté par gUI (Mastodon) . Évalué à 7.
Tu avoues donc ton incompétence… Enfin !
En théorie, la théorie et la pratique c'est pareil. En pratique c'est pas vrai.
[^] # Re: Mes impressions
Posté par xcomcmdr . Évalué à -3.
En fait je manipule directement les logic gates de nos jours.
Le code machine c'est dépassé.
"Quand certains râlent contre systemd, d'autres s'attaquent aux vrais problèmes." (merci Sinma !)
[^] # Re: Mes impressions
Posté par kna . Évalué à 9.
avec des papillons
[^] # Re: Mes impressions
Posté par Fulgrim . Évalué à 5.
Quand le dev est compétent, il sait qu'il va devoir se méfier de faire du C
[^] # Re: Mes impressions
Posté par Graveen . Évalué à 6.
Difficile de comparer C et C#. J'utilise intensement les 2, et bon voilà quoi, le C# pour les applis graphiques desktop Windows, le C pour l'embarqué.
L'article est intéressant, et montre des techniques d'optimisation pour l'utilisation du GC (le fond étant: "effectivement, le GC c'est lourd, lent et imprévisible"), et une recherche dans ce sens donne des resultats, mais la complexité induite est loin d'être négligeable.
[^] # Re: Mes impressions
Posté par Colin Pitrat (site web personnel) . Évalué à 2. Dernière modification le 20 septembre 2022 à 10:53.
Quand le dev est compétent il choisit son langage en fonction du problème qu'il veut résoudre…
Et dans 99.9% [+/-0.1%] des cas c'est Rust [source: sondage sur un échantillon représentatif de devs compétents, N=1].
[^] # Re: Mes impressions
Posté par barmic 🦦 . Évalué à 4.
et dans les 99 autres % (le bon dev n'est pas forcément un bon statisticien) il choisi ocaml
https://linuxfr.org/users/barmic/journaux/y-en-a-marre-de-ce-gros-troll
[^] # Re: Mes impressions
Posté par Anthony Jaguenaud . Évalué à 3.
Comment as-tu évalué que ton N est compétent ?
[^] # Re: Mes impressions
Posté par Gil Cot ✔ (site web personnel, Mastodon) . Évalué à 1.
bah con et pétant plus haut que son rond
~-~>[]
“It is seldom that liberty of any kind is lost all at once.” ― David Hume
[^] # Re: Mes impressions
Posté par Christophe . Évalué à 9.
Sans faire du C ? Vu le niveau de détail dans la gestion de la mémoire, ça pourrait tout aussi bien être du C…
Je ne suis pas sûr qu'on ait déduit la même chose de la lecture de cet article: pour moi, il montre surtout que le GC (et donc, la gestion mémoire) doit être finement pris en compte pour espérer rivaliser avec un langage sans GC.
Tout ça pour atterir à un code bien plus alambiqué et incompréhensible que son équivalent en C, d'ailleurs.
Non, c'est le GC (et/ou le compilateur) qui donnent un résultat moins efficace dans ce scénario. Et pour un langage de haut niveau comme C#, qui inclut un GC, je n'y vois rien de choquant. Le code de départ est maintenable; celui d'arrivée j'ai quelques doutes !
[^] # Re: Mes impressions
Posté par xcomcmdr . Évalué à 5.
Le truc c'est que tu n'arrive pas à un souci de perf dans 99,9 pourcent des cas.
Le jour où tu as besoin de code unsafe (ou même juste des Span ou ArrayPool, qui restent du code managé) , OK c'est possible d'en insérer là où tu en as besoin.
Au lieu d'être obligé de changer de langage, ce qui amènerait pas mal de souci/efforts d'intégration avec le reste du code.
"Quand certains râlent contre systemd, d'autres s'attaquent aux vrais problèmes." (merci Sinma !)
[^] # Re: Mes impressions
Posté par damaki . Évalué à 4. Dernière modification le 18 septembre 2022 à 14:32.
J'ajouterais que si tu gérais la libération de la mémoire à la main, tu pourrais aussi avoir des problèmes de performance. Les mécanismes de GC améliorent la perf de l'allocation mémoire à court terme au détriment de la désallocation lorsque le GC tourne. Les problématiques de fragmentation existent aussi quand on alloue/désalloue à la main, donc ça n'est un argument ni dans un sens ni dans l'autre.
[^] # Re: Mes impressions
Posté par devnewton 🍺 (site web personnel) . Évalué à 10.
Comme je le signalais dans le précédent débat, certaines optimisations sont valables avec un GC ou avec une gestion manuelle de la mémoire.
Depuis longtemps, on a tous compris qu'un free, c'est pas gratuit !
Le post ci-dessus est une grosse connerie, ne le lisez pas sérieusement.
[^] # Re: Mes impressions
Posté par Watchwolf . Évalué à 5.
Je suis d'accord, l'article donne plutôt l'impression dire que que pour être aussi performant il faut être illisible et inmaintenable.
Quand on travail en entreprise, qu'on reprends des projets existants et que quelqu'un d'autres reprendra notre projet, la lisibilité et la compréhension sont un point plus important que les performances.
Il faut mieux ajouter un peu de mémoire, qu'écrire du code illisible.
# Sécurité de la mémoire sans C ni GC
Posté par tuxmain (site web personnel) . Évalué à 5.
En Rust on gère la mémoire aussi précisément qu'en C, mais avec (presque) autant d'aisance qu'avec un GC, sans le runtime du GC, et sans le risque de faire des bêtises.
[^] # Re: Sécurité de la mémoire sans C ni GC
Posté par barmic 🦦 . Évalué à 9. Dernière modification le 18 septembre 2022 à 21:17.
Il faut garder une certaine sérénité rust ne fait pas tout. Ils continuent de bosser sur le borrow checker encore de version en version parce que tu as des cas où tu es très très loin de "l'aisance d'un gc sans runtime".
Il est très bien, je suis pas entrain de dire que c'est mauvais ou une fausse bonne idée, mais c'est pas (encore ?) le meilleur des 2 mondes sans aucun accroc.
https://linuxfr.org/users/barmic/journaux/y-en-a-marre-de-ce-gros-troll
# Le but d’un GC n’a jamais été les performances
Posté par SpaceFox (site web personnel, Mastodon) . Évalué à 10.
Dans la plupart des cas, l’intérêt d’avoir un GC dans le langage, c’est de ne pas avoir à gérer la mémoire. Et donc :
Mais oui, ça se fait au dépend des performances : même dans le cas où le GC ne nettoie jamais rien, le simple fait de lui permettre de pouvoir passer un jour ajoute une surcharge de travail au système. C’est au point qu’on considère qu’en première approche, un GC doit passer le moins souvent possible – sauf si le passer rarement provoque un blocage complet du système si long que la solution n’est plus applicable.
D’autre part, des techniques de programmation orienté sûreté ou fiabilité ont un impact négatif sur la pression mémoire. Par exemple les objets immutables ont beaucoup d’avantages, mais peuvent vite conduire à la création d’une grande quantité d’objets, qui devront être gérés par le GC même si leur vie est très courte (et donc n’utilisent pas significativement plus de mémoire que leur pendants mutables).
En fait, si le GC devient un problème pour les performances, ça peut vouloir dire trois choses :
Le point 1 se détecte facilement en espionnant l’utilisation mémoire et l’activité du GC pendant l’exécution du programme ; le point 2 en analysant un dump mémoire qui contient plein d’objets qui ne devrait pas y être. Ça ne veut pas dire que ces points sont faciles à corriger.
Le point 3 peut très rarement se corriger avec des bidouilles de code ; en en particulier ne peut jamais se corriger efficacement avec des magouilles lourdes du type de celles présentées dans l’article, parce que dans ce cas on a le pire des deux mondes : un code difficile à comprendre (donc à maintenir et sujet à bugs) et la surcharge d’un GC. De plus, beaucoup de ces magouilles (au moins en Java, langage que je connais le mieux) sont au mieux obsolètes : le compilateur puis le GC arrivent très bien à comprendre ce qu’il faut faire sans ces indications, qui sont donc superflues et alourdissent le code pour rien.
Enfin, les problèmes de GC sont très dépendants du contexte exact d’exécution. Sur ce point, j’ai énormément de mal à faire confiance à des microbenchmark.
Je ne prétends pas avoir un métier représentatif, mais en 12 ans à faire du Java de façon professionnelle sur des sujets variés (y compris de l’Android), tous les problèmes de pression mémoire que j’ai rencontrés tombent dans les deux premiers cas. Je dirais trois quarts tiers de fuites mémoire et un quart de manque réel de mémoire dans le paramétrage, à la louche (souvent suite à des jeux de données irréaliste avant d’arriver en production). Et même au-delà de ça, les problèmes d’occupation mémoire que j’ai croisés sont plutôt rares, sauf sur les vieux Android : le facteur limitant des programmes que j’ai croisés sont généralement les I/O1, ou des grosses erreurs de programmation (ne me faites pas dire ce que je ne dis pas : bien sûr qu’on aurait pu faire plus rapide avec d’autres langages, mais sur les cas que j’ai croisé, une fois les erreurs de programmation corrigées, on a toujours été suffisamment rapides).
En conclusion, lorsqu’on utilise un langage à GC, on devrait s’astreindre à conserver un code le plus lisible possible, et à ne faire des bizarreries pour gérer la mémoire que de façon très exceptionnelle et dans des contextes où il a été prouvé, en conditions réelles, que l’impact vaut la perte de lisibilité.
Exception : un progicel IBM – maintenant revendu – qui était programmé en allant tellement loin dans le genre Serious Enterprise Programing caricatural qu’il arrivait à être limité par le CPU. Mais le code était vraiment horrible pour en arriver là. ↩
La connaissance libre : https://zestedesavoir.com
[^] # Re: Le but d’un GC n’a jamais été les performances
Posté par devnewton 🍺 (site web personnel) . Évalué à 10. Dernière modification le 19 septembre 2022 à 09:31.
Peut être que la gestion de la mémoire devrait être plus délégué à l'OS ?
Quel est le bon moment pour lancer un ramassage de miettes (ou pour lancer les free/delete en gestion manuelle) ?
Quand on manque de mémoire !
Mais chaque programme a son propre GC (ou gestion manuelle) et décide donc des conditions de détection du manque sans tenir compte des autres programmes.
Il faut s'imaginer dans un train:
Peut être qu'un contrôleur pourrait organiser tout ça pour dire : ces 4 places sont libres, toi le java tu vas là, ah attends le C a besoin d'une place range ton sac, ah va plus vite, car le Go est lent…
Le post ci-dessus est une grosse connerie, ne le lisez pas sérieusement.
[^] # Re: Le but d’un GC n’a jamais été les performances
Posté par groumly . Évalué à 10.
Et parfois, il se prend un nouveau siège à chaque fois qu’il regarde par la fenêtre, sans pour autant rendre celui qu’il avait avant. Voire tente de manger le sandwich du voisin en étant persuadé que c’est le sien, se prends une patate par le contrôleur et se fait virer du train.
Parfois aussi, il cherche sa bouteille dans son sac en pensant en avoir qu’une, en sort 4, devient contrôleur et décide de détourner le train vers Marseille au lieu de Brest.
Le programme C, c’est vraiment un boulet en fait.
Linuxfr, le portail francais du logiciel libre et du neo nazisme.
[^] # Re: Le but d’un GC n’a jamais été les performances
Posté par devnewton 🍺 (site web personnel) . Évalué à 10.
J'ai oublié le programme Rust qui explique à tout le monde qu'il faut s'assoir comme lui !
Le post ci-dessus est une grosse connerie, ne le lisez pas sérieusement.
[^] # Re: Le but d’un GC n’a jamais été les performances
Posté par SpaceFox (site web personnel, Mastodon) . Évalué à 8.
D’ailleurs les GC de Java sont liés aux implémentations et pas au langage lui-même, et il en sort régulièrement de nouveaux. Les raisons de ces nouveaux GC sont diverses :
C’est d’autant plus perturbant que le GC par défaut peut changer, être déprécié ou même supprimé, ce qui rends plein de trucs complètement inutiles.
Je ne sais pas si les autres langages sont aussi souples sur la gestion de leur GC.
La connaissance libre : https://zestedesavoir.com
[^] # Re: Le but d’un GC n’a jamais été les performances
Posté par Sébastien Koechlin . Évalué à 8.
Je trouve qu'il manque un aspect et que c'est trompeur.
Il est effectivement possible de rendre de la mémoire pour les autres processus, mais ce n'est pas le cas courant. Cela demande de mapper explicitement de la mémoire, et de la rendre lorsqu'on n'en a plus besoin. Cela demande un artifice qui complexifie le code et ajoute une nouvelle source de bugs. (d'après la page de malloc(3) c'est effectivement le cas avec une glibc moderne, un kernel >= 4.7 et pour les allocations unitaires au dessus de 128k).
Au niveau OS, les programme en C allouent leur mémoire dans un seul segment appelé le tas, dont la taille est ajustée avec sbrk(2). Cette taille de tas est augmenté lorsque la mémoire libre n'est pas suffisante; a ma connaissance elle n'est jamais diminuée car cela nécessiterait une défragmentation de l'espace mémoire du processus.
Il y a dix ans (la dernière fois que j'ai testé), le GC Java fonctionnait également sans jamais rendre de mémoire (la consommation augmentait jusqu'à la valeur limite de Xmx). Un GC générationnel devrait pouvoir rendre de la mémoire, mais serait obligé de ré-allouer quasiment la même chose au prochain passage. Je doute qu'il le fasse.
En Go, j'ignore comment ça se passe, mais je serais surpris que le GC s'amuse à rendre de la mémoire en fonctionnement normal.
[^] # Re: Le but d’un GC n’a jamais été les performances
Posté par SpaceFox (site web personnel, Mastodon) . Évalué à 4. Dernière modification le 19 septembre 2022 à 11:47.
La possibilité de pouvoir rendre de la mémoire à l’OS fait partie des possibilités des nouveaux GC de Java dont je parlais dans un autre message. Cf cet article pour plus de détails. G1 GC est le GC par défaut de Java depuis Java 9 et le fait avec les réglages par défaut (et a été amélioré sur ce point depuis Java 12).
D’une façon plus générale, Java est un langage qui évolue significativement : des connaissances sur le langage qui datent de 10 ans datent d’avant Java 8 ; on ne code plus en Java maintenant comme il y a 10 ans, idem pour tous les paramétrages possibles (les GC par exemple). D’ailleurs, beaucoup des critiques contre Java ont été justifiées à une époque, mais n’ont plus tellement lieu d’être aujourd’hui.
La connaissance libre : https://zestedesavoir.com
[^] # Re: Le but d’un GC n’a jamais été les performances
Posté par devnewton 🍺 (site web personnel) . Évalué à 6.
Go rends de la mémoire "régulièrement":
https://pkg.go.dev/runtime/debug#FreeOSMemory
Le post ci-dessus est une grosse connerie, ne le lisez pas sérieusement.
[^] # Re: Le but d’un GC n’a jamais été les performances
Posté par Christophe B. (site web personnel) . Évalué à 6.
Comme indiqué précédemment : le Go est lent
alors il survole la question
OK je sors …
[^] # Re: Le but d’un GC n’a jamais été les performances
Posté par pulkomandy (site web personnel, Mastodon) . Évalué à 10.
Attention à ne pas mélanger 2 choses: sur un système moderne (après 1990) on a de la mémoire virtuelle et une MMU.
Cela veut dire qu'il faut bien distinguer l'allocation d'espace mémoire dans un processus, et l'allocation de mémoire physique pour remplir cet espace.
L'ajustement de taille avec sbrk, ça permet seulement de réserver de l'espace mémoire, qui du coup ne sera plus disponible pour d'autres choses utilisant de la mémoire (mmap, la pile d'exécution, …). L'espace mémoire étant isolé dans chaque processus, ça n'a pas de sens de libérer de l'espace mémoire à l'usage d'un autre processus.
D'autre part, il y a la mémoire physique. Là, on peut allouer et désallouer page par page (4Ko habituellement, mais on commence à voir des "huge pages" de 1Mo pour réduire la charge de travail du MMU) et les pages libérées peuvent être utilisées par d'autres programmes. Il n'y a pas de problème de fragmentation, les pages sont de taille fixe et peuvent être insérées à n'importe quelle adresse dans l'espace mémoire d'un processus.
Même en ayant réservé de l'espace avec sbrk, on est pas obligé de garder cet espace entièrement rempli de pages mémoires disponibles. On peut allouer les pages pour remplir cet espace au moment ou elles sont utilisées, et les libérer lorsque c'est possible ou nécessaire.
La raison pour laquelle on ne le fait pas immédiatement dès qu'une page est disponible, ce sont les performances. Déjà le fait de reconfigurer le MMU pour ajouter ou enlever une page coûte pas mal de temps, mais en plus, il faut effacer le contenu de la page, afin que une autre application ne puisse pas y trouver des traces de l'occupant précédent (ce serait embêtant pour la sécurité du système). Donc ce mécanisme de remise à disposition de page mémoires peut être déclenché seulement lorsque le système commence à être à court de pages à allouer, il va pouvoir demander aux applications de faire du ménage si elles peuvent et de retourner les pages inutilisées à ce moment là.
[^] # Re: Le but d’un GC n’a jamais été les performances
Posté par Sébastien Koechlin . Évalué à 3.
Hello,
Ce que tu dis est vrai. On peut tout à fait mapper et démapper des pages. Mais le mécanisme utilisé dans la libc avec malloc par exemple, qui s'appuie sur le tas; ne l'utilise pas (sauf pour les grosses allocations).
Il gère juste une zone mémoire, qu'il agrandit au besoin.
# L'abstraction c'est bien
Posté par pulkomandy (site web personnel, Mastodon) . Évalué à 10.
J'ai fait du dev en Java pour des cibles embarquées avec quelques centaines de kilo-octets de RAM. Avec un garbage collector.
Et ben on était bien content, non pas parce que c'est rapide, mais surtout parce que ça permettait de déplacer les objets en mémoire de façon transparente pour le code. On pouvait donc défragmenter la mémoire et ainsi libérer de grands espaces contigus pour pouvoir allouer de gros objets.
De la même façon, les stacks pour les threads pouvaient être allouées dynamiquement par tout petits blocs (quelques dizaines ou centaines d'octets à la fois) en fonction des besoins de chaque thread.
La consommation mémoire était donc bien inférieure à un code essayant de faire la même chose en C. Et ça justifiait largement de dédier un peu de puissance CPU au garbage collector.
Suivre le flux des commentaires
Note : les commentaires appartiennent à celles et ceux qui les ont postés. Nous n’en sommes pas responsables.