Скорость выполнения ссылок против указателей


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

Что я хотел бы знать, так это какие виды оптимизации возможны на ссылках, а не на указателях?

Обратите внимание, что речь шла о скорости выполнения, а не об использовании памяти.

5 10

5 ответов:

Есть некоторые преимущества JIT-компиляции , упомянутые в Википедии:

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

    Компиляция может быть оптимизирована для целевого процессора и модели операционной системы, в которой выполняется приложение. Например JIT может выбрать SSE2 CPU инструкции когда он обнаруживает, что процессор поддерживает их. С помощью статического компилятора необходимо написать две версии кода, возможно, используя встроенную сборку. Система способна собирать статистические данные о том, как программа на самом деле работает в среде, в которой она находится, и она может переупорядочивать и перекомпилировать для оптимальной производительности. Однако некоторые статические компиляторы могут также принимать информацию профиля в качестве входных данных.
  1. система может выполнять глобальную оптимизацию кода (например, встраивание библиотечных функций) без потери преимуществ динамической компоновки и без накладных расходов, присущих статическим компиляторам и компоновщикам. В частности, при выполнении глобальных встроенных подстановок статический компилятор должен вставлять проверки во время выполнения и гарантировать, что виртуальный вызов произойдет, если фактический класс объекта переопределяет встроенный метод.
  2. хотя это возможно со статически скомпилированными языками сбора мусора, система байт-кода может более легко переупорядочить память для лучшего кэша. использование.

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

В C++ есть два преимущества ссылок, связанных с аспектами оптимизации:

  1. Ссылка является постоянной (относится к одной и той же переменной в течение всего времени ее существования)

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

  2. Предполагается, что ссылка ссылается на что-то (нет нулевой ссылки)

    Ссылка, которая "ни на что не ссылается" (эквивалентна нулевому указателю), может быть создана, но это не так просто, как создать нулевой указатель. Из-за этого проверка ссылки на NULL может быть опущена.

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

Вообще говоря, ссылки позволяют ссылаться на один и тот же объект из разных мест.

Указатель-это имя механизма для реализации ссылок. C++, Pascal, C... имея указатели, C++ предлагает другой механизм (с немного другими случаями использования), называемый "ссылка", но по существу это все реализации общей концепции ссылки.

Таким образом, нет никакой причины, по которой ссылки по определению быстрее/медленнее указателей.

Реальное разница заключается в использовании JIT или классического "переднего" компилятора: JIT может учитывать данные, которые недоступны для переднего компилятора. Это не имеет ничего общего с реализацией понятия "референт".

Другие ответы верны.

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

Ссылка на объект в управляемом фреймворке сильно отличается от переданной ссылки в C++. Чтобы понять, что делает их особенными, представьте себе, как на машинном уровне обрабатывался бы следующий сценарий без ссылок на объекты, собранные мусором: метод " Foo " возвращает строку, которая хранится в различных коллекциях и передается в разные части кода. После того, как строка больше не нужна, должна быть возможность восстановить всю память, используемую для ее хранения, но неясно, что именно фрагмент кода будет последним, кто использует строку.

В системе без GC каждая коллекция либо должна иметь свою собственную копию строки, либо должна содержать что-то, содержащее указатель на общий объект, который содержит символы в строке. В последнем случае общий объект должен каким-то образом знать, когда последний указатель на него будет удален. Существует множество способов, которыми это можно обрабатывать, но существенным общим аспектом всех из них является то, что общие объекты нужно получать уведомления, когда указатели на них копируются или уничтожаются. Такое уведомление требует работы.

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