Est-il possible d’obtenir un programme Java plus rapide que le même programme (optimisé) en C?

En ce qui concerne le fait que les optimisations C / C ++ sont produites au moment de la compilation, les optimisations Java sont produites au moment de l’exécution. Est-il possible d’obtenir un programme Java plus rapide que le même programme (optimisé) en C?

Je comprends que les optimisations d’exécution peuvent être meilleures que le temps de compilation. C’est pourquoi je me demande si le gain de ces optimisations peut être comparé aux frais généraux liés à l’exécution de la machine virtuelle Java.

En théorie, oui. En pratique, c’est très improbable.

L’une des hypothèses fondamentales est que C / C ++ est compilé une fois pour une cible d’opcode binary et que Java est compilé pour la machine spécifique sur laquelle il s’exécute. Cela devrait donner un avantage à Java. Mais la réalité est que même le C / C ++ peut avoir plusieurs chemins d’optimisation, sélectionnés dynamicment au moment de l’exécution, et tirer le meilleur parti des avantages de la compilation avec une cible spécifique.

Inversement, comme l’a déclaré Rekin, la machine virtuelle Java doit établir un profil dynamic du programme Java pour savoir quoi optimiser et comment. Le profilage est une opération coûteuse en soi, et cette surcharge ne peut pas être éliminée de la JVM Java. D’autre part, sélectionner le bon ensemble d’optimisation pour la charge de travail actuelle peut donner un avantage. En pratique, la plupart des programmes C (mais pas tous 🙂 sont bien adaptés à leur tâche et il rest peu à optimiser à l’aide de techniques de profilage.

Il existe d’autres effets en Java qui éliminent complètement ces problèmes de compilation. Probablement en première position, le ramasse-miettes.

La première mission de Garbage Collector consiste à faciliter la programmation, à prendre en charge et à éviter l’un des plus redoutables bogues récurrents de C / C ++, les memory leaks. Cette fonctionnalité à elle seule justifie la grande utilisation de Java dans de nombreux environnements indussortingels.

Cependant, cela a un coût. Un très grand. Selon des études, il est nécessaire de disposer d’environ 5 fois la quantité de mémoire ssortingctement nécessaire pour que le ramasse-miettes fonctionne avec un minimum de temps système. Ainsi, chaque fois qu’une telle quantité de mémoire fait défaut, la charge de travail du GC commence à devenir importante, ce qui réduit considérablement les performances.

Inversement, il peut arriver, dans certaines circonstances, que la libération de l’algorithme des frais d’allocation de mémoire puisse permettre de modifier l’algorithme et d’en adopter un meilleur, plus rapide. Dans de telles circonstances, Java peut prendre l’avantage et être plus rapide qu’un programme C.

Mais comme vous pouvez le deviner, ceci est rare …

Le fait que les programmes C / C ++ soient spécifiquement écrits pour une plate-forme spécifique et directement compilés en code machine, les rapproche davantage de la plate-forme logicielle / matérielle qu’ils exécutent. Par conséquent, ils seraient plus rapides.

L’optimisation Java est intégrée à la machine virtuelle Java et la meilleure optimisation (en termes de rapidité d’exécution du programme) est obtenue avec la méthode JTI (Just in Time) de traitement du bytecode. Bien que JTI se soit avéré plus gourmand en mémoire.

Ainsi, la comparaison de ces stratégies montre clairement que le code natif C / C ++ serait plus rapide; en tant que JVM ont encore quelques frais généraux pour convertir le bytecode en natif, même avec JTI.

Mais c’est le prix payé pour la plate-forme en dépendance et java étant plus portable.

Tiré de quand java est-il plus rapide que c ++ (ou quand JIT est-il plus rapide que précompilé)? , J’ai trouvé une partie du scénario où l’exécution de Java pouvait surperformer C / C ++

Beaucoup d’allocations mémoire / désallocations. Les principales machines virtuelles ont des sous-systèmes de mémoire extrêmement efficaces, et la récupération de place peut s’avérer plus efficace que de demander une libération explicite (de plus, elle peut déplacer des adresses de mémoire et autres si elle le souhaite vraiment).

Accès efficace via des hiérarchies profondes d’appels de méthodes. La JVM est très efficace pour éliminer tout ce qui n’est pas nécessaire, ce qui est généralement meilleur, selon mon expérience, que la plupart des compilateurs C ++ (y compris gcc et icc). Cela tient en partie au fait qu’il peut effectuer une parsing dynamic au moment de l’exécution (c’est-à-dire qu’il peut suroptimiser et ne désoptimiser que s’il détecte un problème).

Encapsulation de la fonctionnalité dans de petits objects de courte durée.

Les frais généraux de la machine virtuelle Java sont énormes. Il doit charger plusieurs classes, qui résident dans des fichiers zip (jar) et doivent être extraites.

Certaines méthodes d’parsing statique seront exécutées pour chaque classe chargée afin de déterminer s’il existe du code inaccessible, des problèmes de type de stack d’opérandes, etc.

Ensuite, un profileur exécute en permanence l’optimisation des parties de code valables, ce qui signifie généralement que ces méthodes doivent être appelées plusieurs milliers de fois avant d’être optimisées.

En plus de tout cela, vous obtenez également le ramasse-miettes.

Je ne peux pas vraiment imaginer qu’un programme C correctement écrit, compilé pour la plate-forme sur laquelle il tourne, soit surperformé par un équivalent Java. Peut-être que si vous atteignez un cas rare où la JVM a une optimisation et où le compilateur C n’a pas cette optimisation implémentée.

J’ai vu Java courir plus vite que C, c’est quand les ressources sont limitées et que le délai de mise sur le marché est plus important. Dans cette situation, vous n’avez pas autant de temps pour écrire le code aussi efficacement que vous le feriez en C et C ++, vous pouvez finir par faire des choses moins efficaces que ce que la JVM fait pour vous. Par exemple, si vous avez besoin du type de choses que la JVM a déjà, cela peut être plus rapide.

Si vous avez des machines avec suffisamment de ressources, le temps de développement est plus coûteux / plus critique et vous pouvez vous retrouver avec un système stable et opérationnel en moins de temps et avoir le temps de profiler / optimiser tandis qu’une équipe C pourrait encore réparer tous les dumps principaux. . Votre kilométrage variera.

Pour les périphériques à ressources limitées, C domine toujours car vous avez le contrôle sur l’allocation des ressources. BTW La plupart des téléphones mobiles fonctionnent maintenant bien avec Java (ou objective-C).