Разве бокс создает мусор in.NET?


Мне интересно, является ли упаковка типа значения в объекте частным случаем или "коробка", построенная .NET, становится мусором (который должен собирать GC) после того, как любые ссылки на него отбрасываются.

Например, StringBuilder.AppendFormat() имеет следующие перегрузки:

StringBuilder.AppendFormat(string format, object arg0);
StringBuilder.AppendFormat(string format, object arg0, object arg1);
StringBuilder.AppendFormat(string format, object arg0, object arg1, object arg2);
StringBuilder.AppendFormat(string format, params object[] args);

Наличие этих дополнительных перегрузок для вызовов с 3 или менее аргументами может указывать на то, что бокс действительно является частным случаем (или что он окупается, с точки зрения производительности, чтобы избежать массива строительство).

Теоретически, использование простого подсчета старых ссылок, возможно, с пулом многоразовых ящиков, было бы допустимой реализацией, потому что не может быть ссылок от одного ящика к другому, только от объектов .NET к ящику.
3 5

3 ответа:

Во-первых, просто чтобы уточнить: создание массива ссылок на объекты-это Не бокс. "Бокс" - это термин с очень специфическим значением в .NET, и я думаю, что его стоит придерживаться.

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

Однако Вы можете иметь кэш для боксерских целей. Действительно, Java делает это для небольших чисел. Если вы напишете:

Integer x = 5;
Integer y = 5;
System.out.println(x == y); // Reference comparison

Тогда это гарантированно напечатает true.

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

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

Вероятно, стоит отметить, что начиная с .NET 2.0, бокс несколько реже, чем раньше. Это происходит довольно часто в привязке и отражении данных, но теперь это менее распространено в простых старых манипуляциях с данными.

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

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

Однако создание массива принципиально отличается от хранения типа значения. Вызов любой перегрузки StringBuilder.AppendFormat всегда будет содержать аргументы, являющиеся типами значений, поскольку параметр типизируется как object, независимо от того, создается массив или нет. Подробные сведения о боксе в разделе "упаковка и распаковка" в .Объем: основы типа.

Вы задаете неправильный вопрос.

Перегрузки, на которые вы указываете, оптимизируются для прямого вызова параметров. Это означает, что компилятор поместит переменные в arg_0, arg_1, arg_2, arg_3, можно иметь больше, но IL имеет только их быстрый доступ. Все остальное проходит через стек в любом случае, и поэтому не намного эффективнее, чем вызов типизированной функции param.

Для вызова типизированной функции param он фактически создает массив позади scenenes и отправить его в функцию как arg_1 (в этом случае, где arg_0 занимает строку).