Производительность C++ по сравнению с Java / C#

Насколько я понимаю, C / C++ создает собственный код для работы на конкретной архитектуре компьютера. И наоборот, такие языки, как Java и C#, работают поверх виртуальной машины, которая абстрагируется от собственной архитектуры. Логически казалось бы невозможным для Java или C# соответствовать скорости C++ из-за этого промежуточного шага, однако мне сказали, что последние компиляторы («горячая точка») могут достичь этой скорости или даже превзойти ее.

Возможно, это скорее вопрос компилятора, чем вопрос языка, но может ли кто-нибудь объяснить на простом английском, как один из этих языков виртуальных машин может работать лучше, чем родной язык?

Java и C# могут выполнять оптимизацию в зависимости от того, как приложение фактически запускается с использованием кода, доступного во время выполнения. например он может встроить код в общую библиотеку, который может фактически изменяться во время работы программы и при этом оставаться правильным.

Peter Lawrey 16.05.2009 23:57

Некоторые фактические измерения, которые необходимо проверить, прежде чем читать много очень сомнительной теории в этих ответах: Shootout.alioth.debian.org/u32/…

Justicle 17.09.2011 02:49
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
119
2
416 495
29
Перейти к ответу Данный вопрос помечен как решенный

Ответы 29

Это могло бы произойти только в том случае, если интерпретатор Java создает машинный код, который на самом деле оптимизирован лучше, чем машинный код, который ваш компилятор генерирует для кода C++, который вы пишете, до такой степени, что код C++ медленнее, чем Java, и стоимость интерпретации.

Однако вероятность того, что это действительно произойдет, довольно низка - если, возможно, у Java нет очень хорошо написанной библиотеки, а у вас есть собственная плохо написанная библиотека C++.

Я также считаю, что есть определенный языковой вес: работая на более низком уровне, с меньшей абстракцией, вы будете разрабатывать более быструю программу. Это не связано с самим исполнением байт-кода.

Brian R. Bondy 28.09.2008 08:31
Ответ принят как подходящий

Как правило, C# и Java могут быть такими же быстрыми или быстрее, потому что JIT-компилятор - компилятор, который компилирует ваш IL при первом запуске - может выполнять оптимизацию, которую не может выполнить скомпилированная программа C++, потому что она может запрашивать машину. Он может определить, является ли машина Intel или AMD; Pentium 4, Core Solo или Core Duo; или если поддерживает SSE4 и т. д.

Программа на C++ должна быть скомпилирована заранее, как правило, со смешанными оптимизациями, чтобы она работала достаточно хорошо на всех машинах, но не оптимизировалась настолько, насколько это могло бы быть для одной конфигурации (например, процессора, набора инструкций, другого оборудования).

Кроме того, некоторые языковые функции позволяют компилятору C# и Java делать предположения о вашем коде, что позволяет ему оптимизировать определенные части, которые просто небезопасны для компилятора C / C++. Когда у вас есть доступ к указателям, существует множество оптимизаций, которые просто небезопасны.

Кроме того, Java и C# могут выполнять распределение кучи более эффективно, чем C++, потому что уровень абстракции между сборщиком мусора и вашим кодом позволяет ему выполнять все сжатие кучи сразу (довольно дорогостоящая операция).

Сейчас я не могу говорить от имени Java по этому следующему пункту, но я знаю, что, например, C# фактически удалит методы и вызовы методов, когда узнает, что тело метода пусто. И он будет использовать такую ​​логику во всем вашем коде.

Итак, как видите, есть множество причин, по которым определенные реализации C# или Java будут быстрее.

Теперь, когда все сказано, в C++ можно сделать определенные оптимизации, которые сведут на нет все, что вы могли бы сделать с C#, особенно в области графики и в любое время, когда вы находитесь рядом с оборудованием. Указатели здесь творят чудеса.

Так что в зависимости от того, что вы пишете, я бы выбрал одно или другое. Но если вы пишете что-то, что не зависит от оборудования (драйвер, видеоигра и т. д.), Я бы не стал беспокоиться о производительности C# (опять же, не могу говорить о Java). Это будет нормально.

Со стороны Java @Swati указывает на хорошую статью:

https://www.ibm.com/developerworks/library/j-jtp09275

Ваши аргументы неверны - программы на C++ создаются для своей целевой архитектуры, им не нужно переключаться во время выполнения.

Justicle 17.09.2011 02:48

@Justicle Лучшее, что ваш компилятор C++ может предложить для разных архитектур, - это обычно x86, x64, ARM и еще много чего. Теперь вы можете указать ему использовать определенные функции (скажем, SSE2), и, если вам повезет, он даже сгенерирует некоторый резервный код, если эта функция недоступна, но это настолько детально, насколько это возможно. Конечно, никакой специализации в зависимости от размеров кеша и прочего.

Voo 18.09.2011 02:46

См. Shootout.alioth.debian.org/u32/… для примеров того, как происходит эта теория нет.

Justicle 19.09.2011 00:27

Если честно, это один из худших ответов. Это настолько необоснованно, что я мог бы просто перевернуть это. Слишком много обобщений, слишком много незнаний (оптимизация пустых функций - это на самом деле только верхушка айсберга). У компиляторов C++ есть одна роскошь: Время. Еще одна роскошь: проверка не проводится. Но узнайте больше в stackoverflow.com/questions/145110/c-performance-vs-java-c/….

Sebastian Mach 04.10.2011 20:08

вы защищаете C++, потому что знаете, что все переходят на JAVA. Все академические университеты и научно-исследовательские институты предпочитают Java в качестве среды моделирования / разработки, и если вы перейдете к разработке на производственном уровне, то опять же C# наиболее широко используется специально для встраиваемых систем. Серверы переходят на Java EE, C++, вероятно, останется выбором для разработчиков настольных приложений, ориентированных только на наивных конечных пользователей.

Johnydep 25.01.2012 15:23

@Justicle Я пошел туда и посмотрел на код C# Mono, который выглядел так, как будто программист на C++ пошел и ошибся код C# в стиле C++. Конечно, он не будет вести себя так, как код C#, и даже поддерживать его не будет. Но я могу написать много действительно сложных вещей, которые относительно эффективны всего в несколько строк кода на C#, потому что он предлагает эти высокоуровневые функции. Помимо большей части кода C#, нет необходимости выполнять очень быструю математическую обработку или ручные манипуляции с регистрами. Все эти сравнения кажутся важными для того, что C++ делает хорошо, а что другие языки делают плохо. Тесты необъективны.

Orion Adrian 25.01.2012 21:01

Кажется, существует неправильное представление или незнание того, когда компилятор C# выполняет большую часть своей работы. Компилятор C# делает большую часть трудной работы во время сборки. С IL невероятно легко работать и оптимизировать, поэтому предполагаемое преимущество бесконечного времени для компиляторов C++ просто не подтверждается так, как некоторые утверждают. В конце концов, вы немного теряете скорость для функций защиты (например, проверки границ индекса), но действительно мощные структуры, которые вы получаете от этого, вместе с простой природой языка обычно окупаются повышением производительности и целевой оптимизации.

Orion Adrian 25.01.2012 21:08

SO @OrionAdrian - 1. Код C# в тестах неправильный, или 2. C# не необходимость, чтобы быть быстрым. Что он?

Justicle 25.01.2012 22:28

@Justicle Чистая необработанная производительность - не единственное соображение, иначе мы бы все вручную кодировали идеальную сборку. Для меня всегда был вопрос: если у меня будет время X на разработку и задача размера Y, что даст мне лучшую производительность Z. И в зависимости от того, что я делаю, разные языки будут иметь лучший Z. C# не пытается чтобы напрямую конкурировать с C++ за то, что он является самым быстрым в тяжелой математической обработке - зачем это было, для этого и нужен C++. C# имеет достойное ядро, но добавляет быстрое и безопасное программирование метаданных, отражение, доступ к базе данных, ORM, MVC и простые в использовании элементы управления Windows. Он делает это быстро.

Orion Adrian 27.01.2012 23:27

@OrionAdrian Идея о том, что использовать другие языки проще или целесообразнее, не имеет отношения к вопросу.

Justicle 29.01.2012 01:51

@Justicle Вопрос заключается в том, как код может работать быстрее с уровнем абстракции виртуальной машины. Во-первых, ключевые, базовые алгоритмы могут быть проще в мире C#, потому что вы можете делать предположения о многих вещах, таких как (де-) выделение памяти. В общем, чем больше предположений вы сделаете, тем быстрее вы это сделаете. Выбор алгоритма будет иметь большее влияние на производительность, чем что-либо еще, и преимущество того, что так много основных частей опыта будет выполнено за вас, состоит в том, что они могут быть супероптимизированы. Распределитель C# работает очень быстро вместе со строками, файловым вводом-выводом и прочим.

Orion Adrian 30.01.2012 19:27

@OrionAdrian, хорошо, круг замкнулся ... См. Shootout.alioth.debian.org/u32/…, где приведены примеры того, что эта теория не реализуется. Другими словами, покажите нам, что ваша теория может быть доказана правильный, прежде чем делать расплывчатые умозрительные утверждения.

Justicle 30.01.2012 23:13

Однако мы все говорим очень концептуально. На практике было бы сложно найти что-то вроде эффективного трассировщика лучей, реализованного на управляемых языках, таких как Java или C#, и есть причина, по которой мобильные устройства возвращаются к C / C++ для собственных приложений (вместо этого Android переключается на C / C++. Java, MS от C# до C / C++ и т. д.). Встроенные системы очень похожи. Тем не менее, это все допустимые точки производительности JIT, но мы также должны помнить о накладных расходах на уровне языка управляемых языков. Например, в C / C++ мои пользовательские типы могут быть выделены ...

stinky472 28.02.2012 22:15

... в стеке (и часто за исключением агрегатов переменного размера или объектов, которые должны сохраняться вне некоторой непосредственной области видимости). Несмотря на то, что Java и C# имеют дополнительный уровень косвенности, когда GC разрешено сжимать кучу, мы, в свою очередь, обычно используем кучу намного больше на этих языках, и распределение кучи по-прежнему обычно составляет сотни циклов по сравнению немногим для стека. Мы также платим большие деньги за косвенное обращение, и приложениям, критичным к производительности, обычно требуется все, чтобы поместиться в кеш, например - в Яве непросто.

stinky472 28.02.2012 22:18

Мы редко видим, чтобы люди, имеющие дело с управляемыми языками, говорили о таких вещах, как строка кэша или шаблоны доступа к памяти, потому что все находится в куче. Эффективный код такого рода обычно непрактичен для чего-либо, кроме массивов простых старых данных. Мы не можем сделать это, скажем, с библиотекой матриц или вручную закодированными растровыми операциями, пиксельными фильтрами, трассировщиками лучей, симуляторами физики, движками частиц, отслеживанием движения в реальном времени, композитингом видео, обработкой звука и т. д. С другой стороны, если это бизнес-приложения, о которых мы говорим, например, или промежуточное ПО для баз данных, я не удивлюсь, обнаружив ...

stinky472 28.02.2012 22:31

... среднее приложение Java, C# или даже Python превосходит средний эквивалент C++, поскольку 1) большинство из них в любом случае фактически реализовано на C / C++ (задействованы библиотеки JNI, собственные реализации .NET или модули Python C), и 2) приведенные выше причины преимуществ JIT-компиляции и 3) эти языки, прежде всего, оптимизируют продуктивность, а программист, который выполняет работу быстрее, просто имеет больше времени на оптимизацию и исправление ошибок.

stinky472 28.02.2012 22:35

@ stinky472 На самом деле DotNet довольно эффективно использует стек. Регистры тоже. Любой настраиваемый тип, использующий структуру, также будет помещен в стек (хотя это проблема реализации). DotNet отслеживает строки кэша, а JIT-компилятор хорошо разбирается в ресурсах такого типа.

Orion Adrian 01.03.2012 19:00

@OrionAdrian Эффективное использование строки кэша сводится к непрерывной памяти. Если у вас есть ArrayList частиц, фундаментальным аспектом того, можно ли его эффективно обойти, является то, действительно ли он непрерывен. По определению, если каждая частица создается с помощью оператора new, она находится в управляемой куче - эффективность теряется. Только типы, унаследованные от System.ValueType, имеют эту особую характеристику среды CLR, заключающуюся в том, что они не размещаются в управляемой куче. Это далеко не большинство типов, и я видел слишком много людей, пытающихся создать что-то вроде экземпляров частиц в куче.

stinky472 02.03.2012 03:18

@OrionAdrian Это не означает, что я полностью согласен с концептуальными различиями и проблемами, определяемыми реализацией. Но тот факт, что оператор new создает данные в управляемой куче (а не в аппаратном стеке), не определяется реализацией, как new определяется в .NET. И это фундаментальный момент, когда управляемые языки обычно плохо работают по сравнению с чем-то вроде C или FORTRAN. Эти последние языки превосходно работают с большими непрерывными буферами данных в критических для производительности циклах: таких областях, как обработка видео.

stinky472 02.03.2012 03:20

Исполняемый код, созданный компилятором Java или C#, не интерпретируется - он компилируется в собственный код «точно в срок» (JIT). Таким образом, первый раз, когда код в программе Java / C# встречается во время выполнения, возникают некоторые накладные расходы, поскольку «компилятор времени выполнения» (он же JIT-компилятор) превращает байтовый код (Java) или код IL (C#) в машинные инструкции машинного кода. Однако в следующий раз, когда этот код будет встречен во время работы приложения, собственный код будет выполнен немедленно. Это объясняет, почему некоторые программы Java / C# сначала кажутся медленными, но затем работают лучше, чем дольше они работают. Хорошим примером является веб-сайт ASP.Net. Самый первый доступ к веб-сайту может быть немного медленнее, поскольку код C# компилируется в собственный код JIT-компилятором. Последующие обращения приводят к гораздо более быстрому веб-сайту - не считая кеширования на стороне сервера и клиента.

Помимо того, что говорили некоторые другие, насколько я понимаю, .NET и Java лучше выделяют память. Например. они могут сжимать память, поскольку она фрагментируется, в то время как C++ не может (изначально, но может, если вы используете умный сборщик мусора).

Или если вы используете лучший распределитель C++ и / или пул объектов. С точки зрения C++, это далеко не волшебство, и все может сводиться к тому, что «распределение кучи» становится таким же быстрым, как и выделение стека.

paercebal 28.09.2008 12:43

Если вы всегда будете размещать все в куче, тогда .NET и Java могут работать даже лучше, чем C / C++. Но вы просто не сделаете этого на C / C++.

Frunsi 06.12.2009 06:42

Языки виртуальных машин вряд ли превзойдут скомпилированные языки, но они могут подойти достаточно близко, чтобы это не имело значения, по (по крайней мере) следующим причинам (здесь я говорю от имени Java, поскольку я никогда не работал с C#).

1 / Среда выполнения Java обычно способна обнаруживать части кода, которые часто выполняются, и выполнять JIT-компиляцию этих разделов, чтобы в будущем они выполнялись на полной скорости компиляции.

2 / Обширные части библиотек Java скомпилированы так, что, когда вы вызываете библиотечную функцию, вы выполняете скомпилированный код, а не интерпретируете. Вы можете увидеть код (на C), загрузив OpenJDK.

3 / Если вы не выполняете массовые вычисления, большую часть времени ваша программа работает, она ожидает ввода от очень медленного (условно говоря) человека.

4 / Поскольку большая часть проверки байт-кода Java выполняется во время загрузки класса, обычные накладные расходы на проверки во время выполнения значительно сокращаются.

5 / В худшем случае требовательный к производительности код может быть извлечен в скомпилированный модуль и вызван из Java (см. JNI), чтобы он работал на полной скорости.

Таким образом, байт-код Java никогда не превзойдет родной машинный язык, но есть способы смягчить это. Большим преимуществом Java (как мне кажется) является стандартная библиотека ОГРОМНЫЙ и кроссплатформенность.

По пункту 2: «2 / Обширные части библиотек Java скомпилированы так, что при вызове библиотечной функции вы выполняете скомпилированный код, а не интерпретируете»: есть ли у вас ссылка на это? Если бы все было действительно так, как вы описываете, я бы ожидал, что мой отладчик будет часто сталкиваться с машинным кодом, но я этого не делаю.

cero 29.09.2008 02:46

Re: cero Отладчики часто используют менее эффективные, но более выразительные пути, и поэтому не являются хорошим маркером для чего-либо, связанного с производительностью.

Guvante 07.10.2008 22:35

Эта библиотека HUGH дает еще один огромный прирост производительности - код библиотеки, вероятно, лучше написан, чем то, что многие программисты будут писать самостоятельно (учитывая ограниченное время и отсутствие специальных знаний) и на Java, по многим причинам программисты часто используют библиотека.

Liran Orevi 04.12.2009 01:20

Я не уверен, как часто вы обнаружите, что код Java будет работать быстрее, чем C++, даже с Hotspot, но я попытаюсь объяснить, как это могло произойти.

Считайте скомпилированный код Java интерпретируемым машинным языком для JVM. Когда процессор Hotspot замечает, что определенные части скомпилированного кода будут использоваться много раз, он выполняет оптимизацию машинного кода. Поскольку ручная настройка Assembly почти всегда быстрее, чем код, скомпилированный на C++, можно предположить, что программно настроенный машинный код не будет плохим тоже.

Итак, для очень повторяющегося кода я мог видеть, где JVM Hotspot могла бы запускать Java быстрее, чем C++ ... до тех пор, пока не вступит в игру сборка мусора. :)

Не могли бы вы расширить утверждение Since hand-tuning Assembly is almost always faster than C++ compiled code? Что вы имеете в виду под "настраиваемой вручную сборкой" и "кодом, скомпилированным на C++"?

paercebal 14.07.2011 07:50

Что ж, это основано на идее, что оптимизатор компилятора следует правилам, а кодеры - нет. Таким образом, всегда будет код, который, по мнению оптимизатора, он не может оптимизировать идеально, в то время как человек мог бы это сделать, взглянув на общую картину или узнав больше о том, что код действительно делает. Я добавлю, что это комментарий трехлетней давности, и я знаю о HotSpot больше, чем раньше, и я легко вижу, что динамическая оптимизация - ОЧЕНЬ хороший способ ускорить выполнение кода.

billjamesdev 14.07.2011 10:03

1. Оптимизация из Hotspot или любой другой JIT по-прежнему является оптимизацией компилятора. JIT имеет преимущество перед статическим компилятором в том, что он может встроить некоторые результаты (часто вызываемый код) или даже выполнять оптимизацию на основе выполняемого процессора, но это все же оптимизация компилятора. . . 2. Я думаю, вы говорите об оптимизации алгоритма, а не о «тонкой настройке сборки». "точная настройка сборки вручную человеком-программистом" не давала лучших результатов, чем оптимизация компилятора более десяти лет. Фактически, человек, играющий со сборкой, обычно отворачивается от любой оптимизации ...

paercebal 14.07.2011 20:46

Хорошо, я понимаю, что использую неправильную терминологию: «оптимизация компилятора», а не «статическая оптимизация». Я хотел бы отметить, что, по крайней мере, в игровой индустрии, совсем недавно, что касается PS2, мы все еще использовали ручную сборку в местах для «оптимизации» для конкретных чипов, которые, как мы знали, были на консоли; кросс-компиляторы для этих новых чипов еще не так сложны, как для архитектур x86. Вернемся к исходному вопросу выше: преимущество JIT заключается в возможности измерения до оптимизации, что является хорошей вещью (TM).

billjamesdev 14.07.2011 21:53

Обратите внимание, что большинство производственных сборщиков мусора также используют рукописный ассемблер, потому что C / C++ его не сокращает.

J D 06.09.2011 02:56

JIT (Just In Time Compiling) может быть невероятно быстрым, потому что он оптимизируется для целевой платформы.

Это означает, что он может использовать любую уловку компилятора, которую поддерживает ваш ЦП, независимо от того, на каком ЦП разработчик написал код.

Базовая концепция .NET JIT работает следующим образом (сильно упрощенная):

Первый вызов метода:

  • Ваш программный код вызывает метод Foo ()
  • CLR смотрит на тип, реализующий Foo (), и получает связанные с ним метаданные.
  • Из метаданных CLR знает, в каком адресе памяти хранится промежуточный байтовый код (IL).
  • CLR выделяет блок памяти и вызывает JIT.
  • JIT компилирует IL в машинный код, помещает его в выделенную память, а затем изменяет указатель функции в метаданных типа Foo (), чтобы он указывал на этот машинный код.
  • Собственный код запущен.

Вызов метода второй раз:

  • Ваш программный код вызывает метод Foo ()
  • CLR проверяет тип, реализующий Foo (), и находит указатель на функцию в метаданных.
  • Собственный код в этом месте памяти запускается.

Как видите, второй раз это практически тот же процесс, что и в C++, за исключением оптимизации в реальном времени.

Тем не менее, есть и другие накладные расходы, которые замедляют управляемый язык, но JIT очень помогает.

Кстати, Джонатан, я думаю, что кто-то все еще голосует против ваших вещей. Когда я проголосовал за вас, у вас был -1 на этом посте.

Brian R. Bondy 28.09.2008 08:21

В некоторых случаях управляемый код может фактически быть Быстрее, чем собственный код. Например, алгоритмы сборки мусора «отметка и очистка» позволяют средам, подобным JRE или CLR, освобождать большое количество недолговечных (обычно) объектов за один проход, при этом большинство объектов кучи C / C++ освобождаются по очереди. время.

От википедия:

For many practical purposes, allocation/deallocation-intensive algorithms implemented in garbage collected languages can actually be faster than their equivalents using manual heap allocation. A major reason for this is that the garbage collector allows the runtime system to amortize allocation and deallocation operations in a potentially advantageous fashion.

Тем не менее, я написал много C# и много C++, и я провел много тестов. По моему опыту, C++ намного быстрее, чем C#, двумя способами: (1) если вы берете код, написанный на C#, переносите его на C++, чтобы быть быстрее, собственный код имеет тенденцию. Насколько быстрее? Что ж, он сильно различается, но нередко можно увидеть улучшение скорости на 100%. (2) В некоторых случаях сборка мусора может замедлить работу управляемого приложения с помощью массово. .NET CLR ужасно справляется с большими кучами (скажем,> 2 ГБ) и может в конечном итоге проводить много времени в сборке мусора - даже в приложениях, которые имеют мало - или даже не имеют - объектов с промежуточной продолжительностью жизни.

Конечно, в большинстве случаев, которые я описал, управляемые языки достаточно быстры, по большому счету, и компромисс между обслуживанием и кодированием для дополнительной производительности C++ просто неуместен.

Проблема в том, что для длительных процессов, таких как веб-сервер, ваша память со временем станет настолько фрагментированной (в программе, написанной на C++), что вам придется реализовать что-то, напоминающее сборку мусора (или перезапускать время от времени, см. IIS ).

Tony BenBrahim 28.09.2008 08:06

Я не наблюдал этого в больших программах Unix, которые должны работать вечно. Они, как правило, написаны на C, который еще хуже для управления памятью, чем C++.

David Thornley 04.12.2009 00:52

Конечно, вопрос в том, сравниваем ли мы реализацию программы в управляемом и неуправляемом коде или теоретическую максимальную производительность языка. Ясно, что неуправляемый код всегда может быть по меньшей мере так же быстро, как и управляемый, поскольку в худшем случае вы можете просто написать неуправляемую программу, которая будет делать то же самое, что и управляемый код! Но большинство проблем с производительностью алгоритмические, а не микро. Кроме того, вы не оптимизируете управляемый и неуправляемый код одинаково, поэтому «C++ в C#» обычно не работает.

kyoryu 04.12.2009 06:27

В C / C++ вы может выделяете краткосрочные объекты в стеке, и вы делаете это, когда это необходимо. В управляемом коде вы не могу, у вас нет выбора. Кроме того, в C / C++ вы может размещаете списки объектов в смежных областях (новый Foo [100]), в управляемом коде вы не можете. Итак, ваше сравнение неверно. Что ж, эта сила выбора ложится бременем на разработчиков, но таким образом они учатся познавать мир, в котором живут (память ...).

Frunsi 06.12.2009 06:39

@frunsi: «в C / C++ вы можете размещать списки объектов в смежных областях (новый Foo [100]), в управляемом коде вы не можете». Это неверно. Типы локальных значений выделяются стеком, и вы даже можете размещать их массивы в стеке в C#. Существуют даже производственные системы, написанные на C#, которые полностью не выделяют память в устойчивом состоянии.

J D 06.09.2011 14:27

@Jon: Хорошо, верно для типов значений и массивов типов значений. Но я писал об объектах (в речи C# мы говорим о всевозможных ссылочных типах). В мире ООП они - это то место, где начинается самое интересное, и куча C# выделяет все эти объекты.

Frunsi 06.09.2011 23:33

Как правило, алгоритм вашей программы будет гораздо более важным для скорости вашего приложения, чем язык. Вы можете реализовать плохой алгоритм на любом языке, включая C++. Имея это в виду, вы, как правило, сможете писать код, который запускается быстрее на языке, который поможет вам реализовать более эффективный алгоритм.

Языки более высокого уровня преуспевают в этом, обеспечивая более легкий доступ ко многим эффективным предварительно созданным структурам данных и поощряя методы, которые помогут вам избежать неэффективного кода. Конечно, иногда они также могут упростить написание кучи действительно медленного кода, так что вам все равно нужно знать свою платформу.

Кроме того, C++ догоняет «новые» (обратите внимание на кавычки) функции, такие как контейнеры STL, автоматические указатели и т. д. - см., Например, библиотеку boost. И иногда вы можете обнаружить, что самый быстрый способ выполнить какую-либо задачу требует такой техники, как арифметика указателей, которая запрещена на языке более высокого уровня, хотя обычно они позволяют вам обращаться к библиотеке, написанной на языке, который может реализовать ее по желанию. .

Главное - знать, какой язык вы используете, связанный с ним API, что он может делать и каковы его ограничения.

Здесь есть несколько хороших ответов на конкретный вопрос, который вы задали. Я хотел бы сделать шаг назад и взглянуть на картину в целом.

Имейте в виду, что на восприятие пользователем скорости написанного вами программного обеспечения влияет множество других факторов, помимо того, насколько хорошо оптимизирует кодогенератор. Вот некоторые примеры:

  • Ручное управление памятью трудно сделать правильно (без утечек), а еще труднее сделать эффективно (освободите память вскоре после того, как вы закончите с ней). Использование GC, как правило, с большей вероятностью приведет к созданию программы, которая хорошо управляет памятью. Готовы ли вы очень усердно работать и откладывать выпуск своего программного обеспечения, пытаясь превзойти сборщик мусора?

  • Мой C# легче читать и понимать, чем мой C++. У меня также есть другие способы убедить себя, что мой код на C# работает правильно. Это означает, что я могу оптимизировать свои алгоритмы с меньшим риском появления ошибок (а пользователям не нравится программное обеспечение, которое дает сбой, даже если оно делает это быстро!)

  • Я могу создавать свои программы на C# быстрее, чем на C++. Это освобождает время для работы над производительностью и по-прежнему доставляет мое программное обеспечение вовремя.

  • Легче написать хороший пользовательский интерфейс на C#, чем на C++, поэтому я с большей вероятностью смогу отодвинуть работу в фоновый режим, пока пользовательский интерфейс остается отзывчивым, или обеспечить прогресс или импульсный интерфейс, когда программе придется на время блокироваться. Это не делает ничего быстрее, но делает пользователей более счастливыми в ожидании.

Все, что я сказал о C#, вероятно, верно и для Java, просто у меня нет опыта, чтобы сказать наверняка.

Мне нравится ответ Орион Адриан, но есть еще один аспект.

Тот же вопрос был задан несколько десятилетий назад относительно языка ассемблера и «человеческих» языков, таких как FORTRAN. И часть ответа похожа.

Да, программа на C++ способна быть быстрее, чем C#, по любому заданному (нетривиальному?) Алгоритму, но программа на C# часто будет так же быстро или быстрее, чем «наивная» реализация на C++ и оптимизированная версия на C++. на разработку уйдет больше времени, и он все равно может превзойти версию C# с очень небольшим отрывом. Так действительно ли оно того стоит?

Вам придется отвечать на этот вопрос один за другим.

Тем не менее, я давний поклонник C++ и считаю его невероятно выразительным и мощным языком, который иногда недооценивают. Но во многих «реальных» проблемах (лично для меня это означает «те, за решение которых мне платят») C# выполнит свою работу быстрее и безопаснее.

Самый большой штраф, который вы платите? Многие программы .NET и Java занимают много памяти. Я видел, как приложения .NET и Java занимают «сотни» мегабайт памяти, тогда как программы на C++ аналогичной сложности едва занимают «десятки» мегабайт.

Если вы программист на Java / C# и изучаете C++, у вас возникнет соблазн продолжить мыслить терминами Java / C# и дословно перевести синтаксис C++. В этом случае вы получаете только ранее упомянутые преимущества нативного кода по сравнению с интерпретируемым / JIT. Чтобы получить наибольший прирост производительности в C++ по сравнению с Java / C#, вам нужно научиться думать на C++ и разрабатывать код специально, чтобы использовать сильные стороны C++.

Перефразируя Эдсгер Дейкстра: [ваш первый язык] калечит разум безвозвратно.
Перефразируя Джефф Этвуд: вы можете писать [ваш первый язык] на любом новом языке.

Я подозреваю, что поговорка «Вы можете писать FORTRAN на любом языке» предшествовала карьере Джеффа.

David Thornley 04.12.2009 00:54

Компиляция для конкретных оптимизаций ЦП обычно переоценивается. Просто возьмите программу на C++, скомпилируйте с оптимизацией для Pentium PRO и запустите на Pentium 4. Затем перекомпилируйте с optimize для Pentium 4. Я провел долгие дни, делая это с несколькими программами. Общие результаты ?? Обычно прирост производительности менее 2-3%. Таким образом, теоретических преимуществ JIT практически нет. Большинство различий в производительности можно наблюдать только при использовании функций обработки скалярных данных, что в конечном итоге потребует точной настройки вручную для достижения максимальной производительности. Такого рода оптимизации медленные и дорогостоящие, что делает их в любом случае непригодными для JIT.

В реальном мире и реальных приложениях C++ по-прежнему обычно быстрее, чем java, в основном из-за меньшего объема памяти, что приводит к лучшей производительности кеша.

Но чтобы использовать все возможности C++, разработчик должен много работать. Вы можете добиться превосходных результатов, но для этого нужно использовать свой мозг. C++ - это язык, который решил предоставить вам больше инструментов, взимая плату, которую вы должны выучить, чтобы иметь возможность хорошо использовать язык.

Вы компилируете не столько для оптимизации ЦП, сколько для оптимизации пути выполнения. Если вы обнаружите, что метод очень часто вызывается с определенным параметром, вы можете предварительно скомпилировать эту подпрограмму с этим параметром в качестве константы, которая может (в случае логического значения, управляющего потоком) исключить гигантские куски работы. C++ не может приблизиться к такой оптимизации.

Bill K 09.10.2009 21:42

Так как же JIT перекомпилируют подпрограммы, чтобы воспользоваться наблюдаемыми путями выполнения, и насколько это важно?

David Thornley 04.12.2009 00:50

@Bill Я могу смешивать две вещи ... но разве предсказание ветвления, выполняемое во время выполнения в конвейере инструкций, не достигает аналогичных целей независимо от языка?

Hardy 08.09.2010 13:00

@ Hardy да, ЦП может предсказывать ветвления независимо от языка, но он не может исключить весь цикл, наблюдая, что цикл ни на что не влияет. Он также не заметит, что mult (0) жестко привязан к возврату 0, а просто заменит весь вызов метода на if (param == 0) result = 0; и избегайте всего вызова функции / метода. C мог бы делать эти вещи, если бы компилятор имел исчерпывающий обзор того, что происходило, но обычно у него не было достаточно информации во время компиляции.

Bill K 08.09.2010 21:26

Вот интересный тест http://zi.fi/shootout/

Всякий раз, когда я говорю об управляемой и неуправляемой производительности, я хотел бы указать на серию, в которой Рико (и Раймонд) сравнивали версии китайско-английского словаря на C++ и C#. Этот поиск Гугл позволит вам прочитать сам, но мне нравится резюме Рико.

So am I ashamed by my crushing defeat? Hardly. The managed code got a very good result for hardly any effort. To defeat the managed Raymond had to:

  • Write his own file I/O stuff
  • Write his own string class
  • Write his own allocator
  • Write his own international mapping

Of course he used available lower level libraries to do this, but that's still a lot of work. Can you call what's left an STL program? I don't think so, I think he kept the std::vector class which ultimately was never a problem and he kept the find function. Pretty much everything else is gone.

So, yup, you can definately beat the CLR. Raymond can make his program go even faster I think.

Interestingly, the time to parse the file as reported by both programs internal timers is about the same -- 30ms for each. The difference is in the overhead.

Для меня суть в том, что неуправляемой версии потребовалось 6 ревизий, чтобы превзойти управляемую версию, которая была простым портом исходного неуправляемого кода. Если вам нужен каждый последний бит производительности (и у вас есть время и опыт, чтобы получить его), вам придется отказаться от управления, но для меня я воспользуюсь преимуществом на порядок, которое у меня есть в первых версиях над 33 % Я получаю, если попробую 6 раз.

ссылка мертва, нашел указанную статью здесь: blogs.msdn.com/b/ricom/archive/2005/05/10/416151.aspx

gjvdkamp 13.03.2011 11:57

Прежде всего, если мы посмотрим на код Раймонда Чена, он явно не очень хорошо понимает C++ или структуры данных. Его код почти достигает низкоуровневого кода C даже в тех случаях, когда код C не имеет преимуществ в производительности (это просто похоже на недоверие и, возможно, отсутствие знаний о том, как использовать профилировщики). Ему также не удалось понять наиболее алгоритмически верный способ реализации словаря (ради Христа он использовал std :: find). Если есть что-то хорошее в Java, Python, C# и т. д. - все они предоставляют очень эффективные словари ...

stinky472 28.02.2012 22:26

Попытки или даже std :: map будут намного лучше по сравнению с C++ или даже хеш-таблицей. Наконец, словарь - это именно тот тип программы, который больше всего выигрывает от высокоуровневых библиотек и фреймворков. Он не столько демонстрирует различия в языке, сколько задействованные библиотеки (из которых я бы с радостью сказал, что C# гораздо более полный и предоставляет гораздо больше инструментов, подходящих для этой задачи). Покажите для сравнения программу, которая манипулирует большими блоками памяти, например, крупномасштабный матричный / векторный код. Это урегулирует это довольно быстро, даже если, как в этом случае, кодеры не знают, что ...

stinky472 28.02.2012 22:29

На самом деле C# не работает на виртуальной машине, как Java. IL компилируется в язык ассемблера, который представляет собой полностью собственный код и работает с той же скоростью, что и собственный код. Вы можете предварительно выполнить JIT-приложение .NET, которое полностью устранит затраты на JIT, и тогда вы будете запускать полностью собственный код.

Замедление с .NET произойдет не потому, что код .NET работает медленнее, а потому, что он делает гораздо больше за кулисами, чтобы делать такие вещи, как сбор мусора, проверка ссылок, сохранение полных кадров стека и т. д. Это может быть довольно мощным и полезным, когда создание приложений, но также требует затрат. Обратите внимание, что вы можете делать все это и в программе на C++ (большая часть основных функций .NET на самом деле является кодом .NET, который вы можете просматривать в ROTOR). Однако, если вы вручную написали те же функции, вы, вероятно, в конечном итоге получили бы гораздо более медленную программу, поскольку среда выполнения .NET была оптимизирована и точно настроена.

Тем не менее, одна из сильных сторон управляемого кода состоит в том, что он может быть полностью проверяемым, т. Е. вы можете убедиться, что код никогда не будет обращаться к памяти других процессов или делать что-то неадекватное, прежде чем вы его выполните. У Microsoft есть исследовательский прототип полностью управляемой операционной системы, который неожиданно показал, что 100% управляемая среда на самом деле может работать значительно быстрее, чем любая современная операционная система, за счет использования этой проверки для отключения функций безопасности, которые больше не нужны управляемым программам. (в некоторых случаях мы говорим как 10x). У SE Radio есть отличный эпизод, рассказывающий об этом проекте.

Я тоже не знаю ... мои программы на Java всегда медленные. :-) Я никогда особо не замечал, чтобы программы на C# были особенно медленными.

На самом деле JVM Sun HotSpot использует "смешанный режим" выполнения. Он интерпретирует байт-код метода до тех пор, пока не определит (обычно через какой-либо счетчик), что конкретный блок кода (метод, цикл, блок try-catch и т. д.) Будет выполняться много раз, а затем JIT компилирует его. Время, необходимое для JIT-компиляции метода, часто занимает больше времени, чем если бы метод должен был быть интерпретирован, если это редко запускаемый метод. Производительность обычно выше для «смешанного режима», потому что JVM не тратит время на JIT-код, который запускается редко, если вообще запускается. C# и .NET этого не делают. .NET JIT выполняет все, что часто тратит время зря.

Одна из наиболее значительных JIT-оптимизаций - это встраивание методов. Java может даже встроить виртуальные методы, если это может гарантировать корректность выполнения. Этот вид оптимизации обычно не может быть выполнен стандартными статическими компиляторами, потому что он требует анализа всей программы, что затруднительно из-за отдельной компиляции (напротив, JIT имеет всю доступную программу). Встраивание методов улучшает другие оптимизации, позволяя оптимизировать большие блоки кода.

Стандартное выделение памяти в Java / C# также происходит быстрее, а освобождение памяти (GC) не намного медленнее, но менее детерминировано.

Обратите внимание, что free и delete также не являются детерминированными, и GC можно сделать детерминированным, не выделяя.

J D 06.09.2011 03:05

Вот еще один интересный тест, который вы можете попробовать на собственном компьютере.

Он сравнивает ASM, VC++, C#, Silverlight, Java-апплет, Javascript, Flash (AS3).

Демонстрация скорости плагина Roozz

Обратите внимание, что скорость javascript сильно зависит от того, какой браузер его запускает. То же самое верно для Flash и Silverlight, потому что эти плагины работают в том же процессе, что и хост-браузер. Но плагин Roozz запускает стандартные файлы .exe, которые запускаются в собственном процессе, поэтому браузер хоста не влияет на скорость.

Вы должны определить «работать лучше, чем ..». Я знаю, вы спрашивали о скорости, но это не все, что имеет значение.

  • Производят ли виртуальные машины больше накладных расходов во время выполнения? Да!
  • У них больше рабочей памяти кушают? Да!
  • У них более высокие затраты на запуск (инициализация среды выполнения и JIT-компилятор)? Да!
  • Они требуют установки огромной библиотеки? Да!

И так далее, предвзято, да;)

С C# и Java вы платите цену за то, что получаете (более быстрое кодирование, автоматическое управление памятью, большая библиотека и т. д.). Но по мелочам торговаться особо некуда: бери весь пакет или ничего.

Даже если эти языки могут оптимизировать некоторый код для выполнения быстрее, чем скомпилированный код, весь подход (IMHO) неэффективен. Представьте себе, что вы каждый день проезжаете 5 миль до рабочего места на грузовике! Это удобно, приятно, вы в безопасности (крайняя зона деформации), а после того, как вы нажмете на газ в течение некоторого времени, он будет даже таким же быстрым, как стандартный автомобиль! Почему у всех нас нет грузовика, чтобы ехать на работу? ;)

В C++ вы получаете то, за что платите, не больше и не меньше.

Цитата Бьярна Страуструпа: «C++ - мой любимый язык со сборкой мусора, потому что он генерирует так мало мусора» текст ссылки

Что ж, я думаю, что он хорошо понимает его недостатки, он также сказал: «C позволяет легко выстрелить себе в ногу; C++ делает это сложнее, но когда вы делаете это, он отрывает вам всю ногу»;)

Frunsi 04.12.2009 14:24

«Требуется ли им установленная огромная библиотека?» Я полагаю, что Java решает эту проблему с помощью головоломки проекта.

toc777 10.03.2011 17:29

«В C++ вы получаете то, за что платите, не больше и не меньше». Пример счетчика: я тестировал реализацию дерева RB в OCaml и C++ (GNU GCC), в котором использовалось исключение для длительного выхода из рекурсии, если добавляемый элемент уже присутствовал, чтобы повторно использовать существующий набор. OCaml был до 6 раз быстрее, чем C++, потому что он не платит за проверку деструкторов при раскручивании стека.

J D 06.09.2011 03:10

@Jon: но в какой-то (позже?) Момент времени он все равно должен уничтожить объекты (по крайней мере, он должен освободить свою память). Также обратите внимание, что исключения предназначены для исключительных случаев, по крайней мере, в C++ это правило следует соблюдать. Исключения C++ могут быть тяжелыми, когда возникают исключения, что является компромиссом.

Frunsi 06.09.2011 23:19

@Jon: может, попробуем повторить тест с times на оболочке. Так что он проверяет всю программу, а не только один аспект. Тогда похожи ли результаты?

Frunsi 06.09.2011 23:36

Для всего, что требует большой скорости, JVM просто вызывает реализацию C++, поэтому вопрос больше в том, насколько хороши их библиотеки, чем в том, насколько хороша JVM для большинства вещей, связанных с ОС. Сборка мусора сокращает вашу память вдвое, но использование некоторых из более привлекательных функций STL и Boost будет иметь тот же эффект, но с во много раз большим потенциалом ошибок.

Если вы просто используете библиотеки C++ и множество его высокоуровневых функций в большом проекте со множеством классов, вы, вероятно, закончите работу медленнее, чем при использовании JVM. За исключением гораздо большего количества ошибок.

Однако преимущество C++ заключается в том, что он позволяет вам оптимизировать себя, иначе вы застрянете на том, что делает compiler / jvm. Если вы создаете свои собственные контейнеры, пишете собственное управление памятью, которое выровнено, используете SIMD и переходите к сборке здесь и там, вы можете ускорить, по крайней мере, в 2-4 раза по сравнению с тем, что большинство компиляторов C++ сделают самостоятельно. Для некоторых операций 16x-32x. Это с использованием тех же алгоритмов, если вы используете лучшие алгоритмы и распараллеливаете, увеличение может быть значительным, иногда в тысячи раз быстрее, чем обычно используемые методы.

Я смотрю на это с нескольких разных точек зрения.

  1. Будет ли управляемый или неуправляемый код работать быстрее, учитывая бесконечное время и ресурсы? Ясно, что ответ заключается в том, что неуправляемый код всегда может, по крайней мере, связать управляемый код в этом аспекте - поскольку в худшем случае вы просто жестко запрограммируете решение с управляемым кодом.
  2. Если вы возьмете программу на одном языке и напрямую переведете ее на другой, насколько хуже она будет работать? Наверное много, для Любые два языка. Большинство языков требуют разных оптимизаций и имеют разные подводные камни. Микропроизводительность часто зависит от знания этих деталей.
  3. При ограниченном времени и ресурсах, какой из двух языков даст лучший результат? Это наиболее интересный вопрос, поскольку, хотя управляемый язык может производить немного более медленный код (при условии, что программа разумно написана для этого языка), эта версия, вероятно, будет создана раньше, что позволит потратить больше времени на оптимизацию.

Очень короткий ответ: при фиксированном бюджете вы добьетесь более высокой производительности Java-приложения, чем приложение C++ (соображения рентабельности инвестиций). Кроме того, платформа Java имеет более достойные профилировщики, которые помогут вам быстрее определять ваши горячие точки.

Прочтите о Динамо HP Labs, интерпретаторе для PA-8000, который работает на PA-8000 и часто запускает программы быстрее, чем изначально. Тогда это совсем не покажется удивительным!

Не думайте об этом как о «промежуточном шаге» - запуск программы уже включает в себя множество других шагов на любом языке.

Часто это сводится к:

  • у программ есть горячие точки, поэтому даже если вы медленнее выполняете 95% кода, который вам нужно запустить, вы все равно можете быть конкурентоспособными по производительности, если вы быстрее на горячих 5%

  • HLL знает о ваших намерениях больше, чем LLL, такой как C / C++, и поэтому может генерировать более оптимизированный код (OCaml имеет даже больше, а на практике часто даже быстрее)

  • JIT-компилятор имеет много информации, которой нет у статического компилятора (например, фактические данные, которые у вас есть на этот раз)

  • JIT-компилятор может выполнять оптимизацию во время выполнения, которую традиционным компоновщикам на самом деле не разрешено делать (например, переупорядочивание ветвей, чтобы общий случай был плоским, или встраивание вызовов библиотеки)

В общем, C / C++ - довольно плохие языки для производительности: относительно мало информации о ваших типах данных, нет информации о ваших данных и нет динамической среды выполнения, которая позволяла бы многое оптимизировать во время выполнения.

Вы можете получить короткие всплески, когда Java или CLR быстрее, чем C++, но в целом производительность будет хуже в течение всего срока службы приложения: см. www.codeproject.com/KB/dotnet/RuntimePerformance.aspx для получения некоторых результатов по этому поводу.

My understanding is that C/C++ produces native code to run on a particular machine architecture. Conversely, languages like Java and C# run on top of a virtual machine which abstracts away the native architecture. Logically it would seem impossible for Java or C# to match the speed of C++ because of this intermediate step, however I've been told that the latest compilers ("hot spot") can attain this speed or even exceed it.

Это нелогично. Использование промежуточного представления по своей сути не снижает производительность. Например, llvm-gcc компилирует C и C++ через LLVM IR (который представляет собой виртуальную машину с бесконечным числом регистров) в собственный код и обеспечивает отличную производительность (часто превосходящую GCC).

Perhaps this is more of a compiler question than a language question, but can anyone explain in plain English how it is possible for one of these virtual machine languages to perform better than a native language?

Вот некоторые примеры:

  • Виртуальные машины с JIT-компиляцией облегчают генерацию кода времени выполнения (например, System.Reflection.Emit в .NET), поэтому вы можете компилировать сгенерированный код на лету на таких языках, как C# и F#, но должны прибегать к написанию сравнительно медленного интерпретатора на C или C++. Например, для реализации регулярных выражений.

  • Части виртуальной машины (например, барьер записи и распределитель) часто пишутся на ассемблере, написанном вручную, потому что C и C++ не генерируют достаточно быстрый код. Если программа нагружает эти части системы, она может превзойти все, что может быть написано на C или C++.

  • Для динамического связывания собственного кода требуется соответствие ABI, что может снизить производительность и исключает оптимизацию всей программы, тогда как связывание обычно откладывается на виртуальных машинах и может извлечь выгоду из оптимизации всей программы (например, обобщенных обобщенных шаблонов .NET).

Я также хотел бы затронуть некоторые проблемы с высоко оцененным ответом paercebal выше (потому что кто-то продолжает удалять мои комментарии к его ответу), который представляет контрпродуктивно поляризованное мнение:

The code processing will be done at compilation time...

Следовательно, метапрограммирование шаблона работает только в том случае, если программа доступна во время компиляции, что часто бывает не так, например невозможно написать конкурентоспособную библиотеку регулярных выражений на обычном C++, потому что он неспособен генерировать код во время выполнения (важный аспект метапрограммирования).

...playing with types is done at compile time...the equivalent in Java or C# is painful at best to write, and will always be slower and resolved at runtime even when the types are known at compile time.

В C# это верно только для ссылочных типов и неверно для типов значений.

No matter the JIT optimization, nothing will go has fast as direct pointer access to memory...if you have contiguous data in memory, accessing it through C++ pointers (i.e. C pointers... Let's give Caesar its due) will goes times faster than in Java/C#.

Люди наблюдали Java превосходит C++ в тесте SOR из теста SciMark2 именно потому, что указатели препятствуют оптимизации, связанной с псевдонимом.

Также стоит отметить, что .NET выполняет специализацию типов для универсальных библиотек после связывания, тогда как C++ не может этого сделать, потому что шаблоны должны быть разрешены перед связыванием. И, очевидно, большое преимущество дженериков перед шаблонами - это понятные сообщения об ошибках.

Я не думаю, что в наши дни производительность нужно учитывать по отношению к скорости обработки сервера (в конце концов, многоядерные процессоры появились на рынке). Он должен быть более определен в зависимости от использования памяти. И в этом случае у java есть небольшой недостаток.
Но все же в целом языки программирования подходят для разных целей. И это их конкурентное поле, на каждом участке разные победители. И я уверен, что Java выиграет в долгосрочной перспективе, поскольку она продолжает развиваться и конкурентоспособность, которую демонстрирует во всех новых функциях, которые она создает. Я нашел здесь связь, который подтвердит мою причину голосования за java

Другие вопросы по теме