Бокс создает мусор в .NET? - PullRequest
       26

Бокс создает мусор в .NET?

5 голосов
/ 09 февраля 2010

Мне интересно, является ли упаковка типа значения в объекте особым случаем или же "ящик", созданный .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 ]

8 голосов
/ 09 февраля 2010

Прежде всего, просто чтобы уточнить: создание массива ссылок на объекты - это , а не бокс. «Бокс» - это термин, имеющий очень специфическое значение в .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 голосов
/ 09 февраля 2010

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

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

Однако создание массива принципиально отличается от создания типа значения. Вызов любой перегрузки StringBuilder.AppendFormat всегда будет блокировать аргументы, которые являются типами значений, потому что параметр имеет тип object, независимо от того, создан массив или нет. Подробное описание бокса см. В разделе «Бокс и распаковка» по адресу .NET: основы типа .

0 голосов
/ 09 февраля 2010

Вы задаете не тот вопрос.

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

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

...