Разве бокс создает мусор 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 ответа:
Во-первых, просто чтобы уточнить: создание массива ссылок на объекты-это Не бокс. "Бокс" - это термин с очень специфическим значением в .NET, и я думаю, что его стоит придерживаться.
Бокссоздает мусор - или, скорее, каждый раз, когда вы боксируете, он создает новый объект, который, вероятно, в конечном итоге станет мусором. (Он не должен стать мусором - у вас может быть ссылка на этот объект до конца жизни приложения; это просто красиво редкий.)
Однако Вы можете иметь кэш для боксерских целей. Действительно, Java делает это для небольших чисел. Если вы напишете:
Integer x = 5; Integer y = 5; System.out.println(x == y); // Reference comparison
Тогда это гарантированно напечатает
Однако это всего лишь небольшой кэш для фиксированного набора типов-это не кэш общего назначения. Вам нужно уравновесить боль от наличия общего кэша со слабыми ссылками (не подсчет ссылок - механизм GC в .NET просто Не подсчитывает ссылки, и вы не могли бы действительно ввести это Просто для упакованных значений) почти наверняка повредит производительности больше, чем небольшая стоимость упаковки, создающей мусор.true
..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 занимает строку).