У бокса и распаковки одинаковый удар по производительности? - PullRequest
7 голосов
/ 04 марта 2012

У бокса и распаковки одинаковый удар по производительности? Или распаковка происходит быстрее, скажем?

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

Спасибо

Ответы [ 3 ]

11 голосов
/ 04 марта 2012

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

Хотя у них разные характеристики производительности: бокс требует выделения нового объекта, но без проверки типов.

Для распаковки на уровне IL нужно только проверить, действительно ли объект, который вы пытаетесь распаковать, является коробочным значением того же типа (или совместимым). Затем вам нужно добавить операцию копирования значения в C # версии распаковки.

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

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

1 голос
/ 10 марта 2017

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

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

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

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

В-третьих, в случае распаковки среде выполнения может потребоватьсявыполнить проверку типа, чтобы определить, является ли операция распаковки на самом деле законной и даст ли правильный результат.В некоторых случаях может быть возможно статически вывести тип объекта, который необходимо распаковать, но это оптимизация компилятора (или функция системы типов), а не прямая связь с выполняемой нами операцией.

* 1011В-четвертых, скрытая долгосрочная стоимость нашего упакованного целого числа состоит в том, что он, как и любой другой ссылочный тип, должен участвовать в сборке мусора.Это означает, что ссылки на него, возможно, должны быть записаны, они должны быть отслежены для определения жизнеспособности и, возможно, должны быть скопированы в другое поколение.Хотя это, конечно, верно для всех ссылочных типов, это фактор, который необходимо учитывать, если мы думаем о производительности на этом уровне.

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

0 голосов
/ 27 сентября 2014

Насколько я знаю, распаковка намного дешевле, чем бокс.Учтите это:

Int32 v1 = 5;

v1 выделяется в стеке.

Object r = v1; // boxing

Компилятор принимает значение v1 и создает на его основе объект.Это занимает некоторое время (по нескольким причинам).

Однако, когда этот код выполняется:

Int32 v2 = r; //unboxing

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

...