Книга знаний

Инф. технологии

Трансляция объектов в машинный код в Delphi

В статье предпринята попытка проанализировать, ведет ли объектный стиль программирования к существенному замедлению кода по сравнению с процедурным стилем.Автор статьи: romix | Редакторы:
Последняя редакция №13 от 08.02.07 | История
URL: http://kb.mista.ru/article.php?id=472

Для проверки, в какой же именно код транслирует Delphi тот или иной пример, я использовал отладчик SoftICE. Чтобы остановить выполнение на нужном фрагменте кода, я даю SoftICE команду

BPX MessageBoxA
(ставлю точку останова на функции MessageBox). Чтобы дать эту команду, я открываю окно отладчика нажатием Ctrl-D, ввожу эту команду и нажимаю Enter.

И, соответственно, вставляю в свой код на Delphi вызов MessageBox (эта системная функция Windows выводит окно предупреждения). Когда срабатывает "бряк" (breakpoint), я выхожу "наверх" из функции нажатием клавиши F12, после чего пошагово исполняю код нажатием клавиш F8 (пошаговое выполнение) или F10 (то же самое, без захода в процедуры). В приведенных ниже примерах кода вызов MessageBox, который я использую только для этой цели (чтобы остановить выполнение в SoftICE), помечен синим цветом.

Простейший пример

В этом примере я просто вывожу сообщение (MessageBox) из метода объекта и из процедуры соответственно. Сгенерированный транслятором машинный код почти не отличается, за исключением передачи в регистре eax ссылки (указателя) на объект в случае с применением ООП.

В объектном стиле В процедурном стиле
program ObjTest;
uses Windows;

type T_TEST = Class
  procedure test();
end;

procedure T_TEST.test();
begin
  MessageBox(0, 'test', 'test',0);
end;

var obj: T_TEST;
begin
  obj:=T_TEST.Create;
  obj.Test();
  obj.Test();
  obj.Free;
end.
program ObjTest;
uses Windows;

procedure test();
begin
  MessageBox(0, 'test', 'test',0);
end;

begin
  Test();
  Test();
end.
mov eax, ebx
call 00403620
mov eax, ebx
call 00403620
...
00403620: 
  push 00
  push 00403640; "test"
  push 00403640; "test"
  push 00
  call User32!MessageBoxA
  ret
call 00401E90
call 00401E90
...
00401E90: 
  push 00
  push 00403640; "test"
  push 00403640; "test"
  push 00
  call User32!MessageBoxA
  ret

Складываем два числа

В объектном стиле В процедурном стиле
program ObjTest;
uses Windows;

type T_TEST = Class
  function add(a,b: Integer):Integer;
end;

function T_TEST.add(a,b: Integer):Integer;
begin
  MessageBox(0, 'test', 'test',0);
  Result:=a+b;
end;

var obj: T_TEST;
begin
  obj:=T_TEST.Create;
  obj.add(2,3);
  obj.add(3,4);
  obj.Free;
end.
program ObjTest;
uses Windows;

function add(a,b: Integer):Integer;
begin
  MessageBox(0, 'test', 'test',0);
  Result:=a+b;
end;

begin
  add(2,3);
  add(3,4);
end.
mov ecx, 00000004
mov edx, 00000003
mov eax, ebx
call 00403620
...
00403620: 
  push ebx
  push esi
  mov esi, ecx
  mov ebx, edx
  push 00
  push 00403640; "test"
  push 00403640; "test"
  push 00
  call User32!MessageBoxA
  lea eax, [ebx+esi]
  pop esi
  pop ebx
  ret
  mov edx, 00000004
  mov eax, 00000003
  call 00401E90
...
00401E90:
  push ebx
  push esi
  mov esi, edx
  mov ebx, eax
  push 00
  push 00403640; "test"
  push 00403640; "test"
  push 00
  call User32!MessageBoxA
  lea eax, [ebx+esi]
  pop esi
  pop ebx
  ret

Передаем параметры через переменные или поля класса

Переделаем этот же пример так, чтобы числа, которые нужно сложить, передавались не через параметры функции, а через поля класса.

В объектном стилеВ процедурном стиле
program ObjTest;
uses Windows;

type T_TEST = Class
  a: Integer;
  b: Integer;
  function add():Integer;
end;

function T_TEST.add():Integer;
begin
  MessageBox(0, 'test', 'test',0);
  Result:=a+b;
end;

var obj: T_TEST;
begin
  obj:=T_TEST.Create;
  obj.a:=2;
  obj.b:=3;
  obj.add();

  obj.a:=3;
  obj.b:=4;
  obj.add();
  obj.Free;
end.
program ObjTest;
uses Windows;

var
  a: Integer;
  b: Integer;

function add():Integer;
begin
  MessageBox(0, 'test', 'test',0);
  Result:=a+b;
end;

begin
  a:=2;
  b:=3;
  add();

  a:=3;
  b:=4;
  add();
end.
  mov dword ptr[ebx+04], 0000003
  mov dword ptr[ebx+08], 0000004
  mov eax, ebx
  call 00403620
  ...
00403620:
  push ebx
  mov ebx, eax
  push 00
  push 00403640; "test"
  push 00403640; "test"
  push 00
  call User32!MessageBoxA
  mov eax, [ebx+04]
  add eax, [ebx+08]
  pop ebx
  ret
  mov dword ptr[004036EC], 0000003
  mov dword ptr[004036F0], 0000004
  call 00401E90
  ...
00401E90:
  push 00
  push 00403640; "test"
  push 00403640; "test"
  push 00
  call User32!MessageBoxA
  mov eax, [004036EC]
  add eax, [004036F0]
  ret

Выводы

Как видим в вышеприведенных примерах, различия малосущественны, и оправданы необходимостью передавать дополнительную переменную - ссылку на объект.

Рекомендуемая литература

Касперски К. "Техника оптимизации программ. Эффективное использование памяти"
http://www.citforum.ru/book/optimize/contents.shtml

Описание | Рубрикатор | Поиск | ТелепатБот | Захваченные статьи | Установки | Форум
© Станислав Митичкин (Волшебник), 2005-2025 | Mista.ru

Яндекс.Метрика