ОТКРЫТОЕ ПОСМОТРЕТЬ ПРИМЕР МЕРДАДА (ОБА ВЕРСИИ)
Я попытаюсь покопаться немного глубже на милых доказательствах Мехрдада, для тех, кто, как я, не очень хорошо читает ассемблерный код. Этот код может быть записан в Visual Studio, когда мы отлаживаем, нажимая Отладка -> Windows -> Сборка.
Версия с использованием REF
Исходный код:
namespace RefTest
{
class Program
{
static void Test(ref object o) { GC.KeepAlive(o); }
static void Main(string[] args)
{
object temp = args;
Test(ref temp);
}
}
}
Язык ассемблера (x86) (показывает только ту часть, которая отличается):
object temp = args;
00000030 mov eax,dword ptr [ebp-3Ch]
00000033 mov dword ptr [ebp-40h],eax
Test(ref temp);
00000036 lea ecx,[ebp-40h] //loads temp address's address on ecx?
00000039 call FD30B000
0000003e nop
}
ВЕРСИЯ БЕЗ REF
Исходный код:
namespace RefTest
{
class Program
{
static void Test(object o) { GC.KeepAlive(o); }
static void Main(string[] args)
{
object temp = args;
Test(temp);
}
}
}
Язык ассемблера (x86) (показывает только ту часть, которая отличается):
object temp = args;
00000035 mov eax,dword ptr [ebp-3Ch]
00000038 mov dword ptr [ebp-40h],eax
Test(temp);
0000003b mov ecx,dword ptr [ebp-40h] //move temp address to ecx?
0000003e call FD30B000
00000043 nop
}
Помимо закомментированной строки, код одинаков для обеих версий: с ref вызову функции предшествует инструкция LEA, без ref мы имеем более простую инструкцию MOV. После выполнения этой строки LEA загрузил регистр ecx с указателем на указатель на объект, тогда как MOV загрузил ecx с указателем на объект. Это означает, что подпрограмма FD30B000 (указывающая на нашу функцию тестирования) в первом случае должна будет сделать дополнительный доступ к памяти, чтобы добраться до объекта. Если мы проверим код сборки для каждой созданной версии этой функции, мы увидим, что в какой-то момент (фактически единственная строка, которая отличается между двумя версиями), сделан дополнительный доступ:
static void Test(ref object o) { GC.KeepAlive(o); }
...
00000025 mov eax,dword ptr [ebp-3Ch]
00000028 mov ecx,dword ptr [eax]
...
Пока функция без ссылки может идти прямо к объекту:
static void Test(object o) { GC.KeepAlive(o); }
...
00000025 mov ecx,dword ptr [ebp-3Ch]
...
Надеюсь, это помогло.