В чем разница между ldsfld и ldstr в IL?

Я прочитал статью о String.Empty vs "" и сам тестирую. Различия между ними приведены ниже.

String.Empty

L_0001: ldsfld string [mscorlib]System.String::Empty

""

L_0001: ldstr ""

После того, как я поговорил с друзьями, они утверждают, что String.Empty быстрее, чем "", потому что под капотом (на уровне сборки) ldstr делает больше 1 круга, чем ldsfld. (Я не могу вспомнить шаги, которые отличают их)

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


person Anonymous    schedule 09.09.2010    source источник
comment
Вы когда-нибудь пытались измерить это в коде?   -  person Yves M.    schedule 09.09.2010
comment
возможный дубликат В чем разница между String.Empty и   -  person Darin Dimitrov    schedule 09.09.2010
comment
@Yves Я пытался выполнить около 1 000 000 циклов, но производительность различается, иногда быстрее, иногда string.Empty.   -  person Anonymous    schedule 09.09.2010
comment
@Darin: я думаю, что это другой вопрос, потому что я говорю на более низком уровне, чем IL (может быть, это управление внутренней памятью).   -  person Anonymous    schedule 09.09.2010


Ответы (3)


Операция ldsfld помещает значение статического поля в стек вычислений, а ldstr помещает ссылку на литерал строки метаданных.

Разница в производительности (если она есть) будет минимальной. Более новые версии компилятора фактически заменяют "" на String.Empty.

Вы также должны учитывать удобочитаемость и ремонтопригодность кода. Используя String.Empty становится ясно, что вы на самом деле имеете в виду пустую строку, а не просто забыли ввести что-то в строковый литерал.

Редактировать:

Я взглянул на созданный собственный код.

С# 3, режим выпуска, x86:

        string a = String.Empty;
0000002a  mov         eax,dword ptr ds:[0356102Ch]
0000002f  mov         dword ptr [ebp-8],eax
        string b = "";
00000032  mov         eax,dword ptr ds:[0356202Ch]
00000038  mov         dword ptr [ebp-0Ch],eax

С# 3, режим выпуска, x64:

        string a = String.Empty;
0000003b  mov         rax,12711050h 
00000045  mov         rax,qword ptr [rax] 
00000048  mov         qword ptr [rsp+28h],rax 
        string b = "";
0000004d  mov         rax,12713048h 
00000057  mov         rax,qword ptr [rax] 
0000005a  mov         qword ptr [rsp+30h],rax 

Итак, в итоге код идентичен.

person Guffa    schedule 09.09.2010
comment
+1 за просмотр сборки, потому что это действительно имеет значение. - person Steven; 09.09.2010
comment
Как вы смотрите на сборку? - person Joe Phillips; 14.06.2018

ldstr — это IL для загрузки определенного токена строки из метаданных.

ldsfld — это IL для загрузки указанного поля, в данном случае это string.Empty.

Другими словами, это совершенно разные операции, которые в данном случае приводят к одному и тому же результату. Как они реализованы на уровне сборки? Что ж, это вполне может зависеть от используемой вами версии CLR. Спросите своих друзей, о какой версии они говорят... настольная (32 или 64-битная? 1, 2, 2SP1, 2SP2, 4?), Compact Framework (опять же, какая версия?), Silverlight (какая операционная система, какая версия ?) Они использовали cordbg в коде, который вы на самом деле обсуждаете, или они сделали это в каком-то образце кода, который, возможно, не был оптимизирован таким же образом?

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

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

person Jon Skeet    schedule 09.09.2010

Отличие от .NET 4.5 в данном случае: ровно ничего. Похоже, JIT теперь обнаруживает этот ldsfld и напрямую вставляет интернированную пустую строку.

Вы можете сказать это, потому что в ‹ 4.5 вы можете изменить значение string.Empty с помощью отражения, и это влияет на код, использующий string.Empty. Неприятно, но возможно. С 4.5 больше не работает. Если вы можете проверить с помощью отражения, вы получите взломанную версию, но код, использующий string.Empty через ldsfld, получит правильную пустую строку, а не взломанную версию.

person Marc Gravell    schedule 31.03.2013