Форум: "Основная";
Текущий архив: 2006.10.15;
Скачать: [xml.tar.bz2];
ВнизИпользование объекта вместо записи Найти похожие ветки
← →
atruhin © (2006-09-03 12:26) [0]Иногда удобно вместо записи использовать объект, например:
Вместо:
record X,Y : integer; end;
Использовать:
class
X, Y : integer;
constructor Create(aX,aY : integer);
end;
Вопрос: какова разница в объеме занимаемой памяти? Т.е. таблицы VMT, доп. информация? И влияет ли на разницу наличие constructor
← →
Юрий Зотов © (2006-09-03 12:59) [1]Сам объект занимает на 4 байта больше аналогичной записи (по нулеврму смещению он содержит неявное поле - ссылку на VMT). Плюс хотя бы одна ссылка на этот объект (он же не может, как запись, располагаться в статической памяти) - еще 4 байта. Размер VMT для разных версий Delphi тоже немного разный, но где-то примерно около сотни байт (конкретно можно посмотреть в System.pas). Плюс таблица полей, таблица свойств, таблица методов... их размер зависит от количества этих самых полей, свойств и методов в секции published (если компиляция идет с $M+). В общем, минимальная разница - примерно байт сто, но может быть и больше.
Влияет ли на разницу наличие constructor - если этот конструктор имеет код, то где-то этот код тоже ведь должен храниться? Он и хранится, в теле самой программы. Плюс небольшие накладные расходы на код вызова конструктора и деструктора.
ИМХО, можно просто создать процедуру типа CreateMyRecord - и тогда овчинка вряд ли стоит выделки.
← →
Джо © (2006-09-03 13:35) [2]> ИМХО, можно просто создать процедуру типа CreateMyRecord
> - и тогда овчинка вряд ли стоит выделки.
Или использовать компилятор BDS 2006 с новым синтаксисом записей, в котором позволены методы в записях.
← →
Palladin © (2006-09-03 13:46) [3]Или использовать, чуть более широкий по возможностям чем Record, Object. В котором позволены методы со времен TP5.5 :)
← →
Джо © (2006-09-03 14:02) [4]> [3] Palladin ©
А у object накладные расходы на служебную информацию (VMT), а именно их и хотят, по возможности, избежать ;)
← →
atruhin © (2006-09-03 14:54) [5]> Размер VMT для разных версий Delphi тоже немного разный,
> но где-то примерно около сотни байт
Да но ведь VMT хранится для класса а не для экземпляра объекта? Тогда это не принципиально.
А вопрос вообще возникает в случае хранения тысяч объектов в памяти, например в TList и т.д., в таких случаях удобнее работать с объектами, а не записями. Т.е. насколько я понял для экземпляра объекта добавляется всего 4 байта, по сравнению с записью?
← →
sniknik © (2006-09-03 14:59) [6]> аА у object накладные расходы на служебную информацию (VMT), а именно их и хотят, по возможности, избежать ;)
не очень красиво, но ... пример в D7type
TMet = record
x, y: integer;
Show: TNotifyEvent;
end;
PMet = ^TMet;
TForm1 = class(TForm)
Button1: TButton;
procedure FormCreate(Sender: TObject);
procedure Button1Click(Sender: TObject);
private
Met: TMet;
procedure MetShow(Sender: TObject);
public
end;
var
Form1: TForm1;
implementation
{$R *.dfm}
procedure TForm1.MetShow(Sender: TObject);
var
LocMet: PMet;
begin
LocMet:= PMet(Pointer(Self));
ShowMessage(IntToStr(LocMet.x + LocMet.y));
end;
procedure TForm1.FormCreate(Sender: TObject);
procedure SetMethod(val: TNotifyEvent);
begin
TMethod(Met.Show).Code:= TMethod(val).Code;
TMethod(Met.Show).Data:= @Met;
end;
begin
SetMethod(MetShow);
Met.x:= 10;
Met.y:= 15;
end;
procedure TForm1.Button1Click(Sender: TObject);
begin
Met.Show(Self);
end;
и удобным это тоже не назовеш... но накладные расходы на VMT избегаются.
ну еще лучше бы вынести всю обработку рекорда в отдельный модуль, тогда чтобы не привязыватся к форме обработчики делать процедурами "of object", но это частности ткак сказать, зачем автору это нужно неясно, может как раз таких/похожих "замоморочек" хочет избежать... а тут, это. ;о)
← →
default © (2006-09-03 18:16) [7]цель замена какая?
← →
tesseract © (2006-09-03 18:23) [8]> [4] Джо © (03.09.06 14:02)
Ну и плюс с приведением типов проблемы будут. Лучше уж запись.
← →
default © (2006-09-03 18:32) [9]цель, как я понимаю, недопустить использование неинициализированных данных
хорошая цель
например, CLR дотнетовская воспринимает обращение к неинициализированных данным(обычно они находятся в стеке) как код не проходящий верификацию:) то есть в безопасной среде - такой код исполнен не будет
так что шаги на пути к безопасному коду я только поощряю:)
← →
Джо © (2006-09-03 23:47) [10]Я как-то для хранения большого количества однотипных объектов использовал (для уменьшения расходов памяти) следующий подход. Внутренне данные хранились в приватном поле класса в динамическом массиве. А наружу торчал аксессор, на лету преобразующий элементы массива в класс, точнее, интерфейс.
Вот упрощенный и несколько схематичный пример, основанный на реальном коде. :) Кажется, есть какой-то "паттерн" такой, забыл только название.unit Points;
interface
uses SysUtils;
type
IPoint = interface
["{245732B1-B9AF-415D-9269-8DC9ACA8A1D3}"]
function GetX: Double;
function GetY: Double;
procedure SetX (const Value: Double);
procedure SetY (const Value: Double);
property X: Double read GetX write SetX;
property Y: Double read GetY write SetY;
// ...
// ...
end;
TPoints = class; // forward declaration
TPoint = record
X,Y: Double;
end;
TPointArray = array of TPoint;
TPoints = class
private
FPointArray: TPointArray; // Массив записей, а не классов!
function GetPoints(Index: Integer): IPoint;
procedure SetPoints(Index: Integer; const Value: IPoint);
public
property Points[Index: Integer]: IPoint read GetPoints write SetPoints; default;
function AddPoint (const X,Y: Double): Integer;
// ...
// ...
end;
implementation
type
TPointClass = class (TInterfacedObject, IPoint)
private
FParent: TPoints;
FParentIndex: Integer;
FX,
FY: Double;
function GetX: Double;
function GetY: Double;
procedure SetX (const Value: Double);
procedure SetY (const Value: Double);
procedure NotifyParent;
public
constructor Create (AParent: TPoints; const FParentIndex: Integer;
const X,Y: Double);
end;
constructor TPointClass.Create(AParent: TPoints; const FParentIndex: Integer;
const X,Y: Double);
begin
inherited Create;
FX := X;
FY := Y;
FParent := AParent;
end;
function TPointClass.GetX: Double;
begin
Result := FX
end;
function TPointClass.GetY: Double;
begin
Result := FY
end;
procedure TPointClass.NotifyParent;
begin
if Assigned(FParent) then
FParent[FParentIndex] := Self
end;
procedure TPointClass.SetX(const Value: Double);
begin
FX := Value;
NotifyParent
end;
procedure TPointClass.SetY(const Value: Double);
begin
FY := Value;
NotifyParent
end;
function TPoints.AddPoint(const X, Y: Double): Integer;
begin
Inc (FCount);
if FCount > FCapacity then
Reallocate;
FPointArray[FCount-1].X := X;
FPointArray[FCount-1].Y := Y;
Result := FCount-1;
end;
// "На лету" преобразует элементы внутреннего массива
// в интерфейс
function TPoints.GetPoints(Index: Integer): IPoint;
begin
Result := TPointClass.Create(Self, Index,
FPointArray[Index].X,FPointArray[Index].Y);
end;
procedure TPoints.SetPoints(Index: Integer; const Value: IPoint);
begin
FPointArray[Index].X := Value.X;
FPointArray[Index].Y := Value.Y;
end;
end.
← →
Германн © (2006-09-04 00:47) [11]Я лично, очень часто использую объект вместо записи. Во-первых, как уже было сказано, поля объекта инициализируются при создании, во-вторых удобно создавать и использовать список таких объектов с помощью TList. Особенно с учётом Д4. Ну а размер меня мало волнует. У меня объекты создаются не очень часто и уничтожаются "как только, так сразу".
← →
GrayFace © (2006-09-04 11:07) [12]> Джо © (03.09.06 14:02) [4]
А у object накладные расходы на служебную информацию (VMT), а именно их и хотят, по возможности, избежать ;)
По-моему, расходы есть только если есть виртуальные методы.
← →
atruhin © (2006-09-04 11:47) [13]Спасибо за ответы. Не уверен в одном моменте.
Разница в объеме памяти между объектами и записями определяется так:
размер памяти для объектов типа:
TTest = class
REC : TMyRecord;
end;
будет
(Sizeof(TMyRecord)+4)*CountObject + SizeOf(VMT)
где CountObject - кол-во созданных объектов.
Это правильно?
← →
oxffff © (2006-09-04 12:15) [14]Нет
← →
atruhin © (2006-09-04 12:32) [15]> [14] oxffff © (04.09.06 12:15)
Почему?
← →
oxffff © (2006-09-04 12:42) [16]taa=record
a:integer;
end;
classA=class
public
b:taa;
procedure abc;virtual;abstract;
end;
showmessage(inttostr(classA.InstanceSize)) // равно 8
← →
oxffff © (2006-09-04 12:47) [17]Размер объекта равен
указатель на VMT (4 байта)
+размер полей
Размер типа
VMT
+dynamic method table
+short string containing class name
+method definition table
+type information table
+instance initialization table
+Automation information table
+interface table
← →
han_malign © (2006-09-04 12:52) [18]
> GrayFace © (04.09.06 11:07) [12]
>
> > Джо © (03.09.06 14:02) [4]
> >А у object накладные расходы на служебную информацию (VMT),
> > а именно их и хотят, по возможности, избежать ;)
> По-моему, расходы есть только если есть виртуальные методы.
- так и есть, причем, если добавить виртуальный метод, то адресс VMT будет лежать не по нулевому смещению, а после полей базовового объекта(из-за чего нужно быть внимательным при приведении объектных типов по record-маске)...
← →
oxffff © (2006-09-04 12:59) [19]> GrayFace © (04.09.06 11:07) [12]
>
> > Джо © (03.09.06 14:02) [4]
> >А у object накладные расходы на служебную информацию (VMT),
> > а именно их и хотят, по возможности, избежать ;)
> По-моему, расходы есть только если есть виртуальные методы.
han_malign
>- так и есть, причем, если добавить виртуальный метод, то адресс VMT >будет лежать не по нулевому смещению, а после полей базовового >объекта>(из-за чего нужно быть внимательным при приведении объектных >типов по record-маске)...
Вы путаете это с С++
Указатель на VMT всегда по нулевому смещению
← →
oxffff © (2006-09-04 13:02) [20]to han_malign
Тут возможно я не прав. Не обратил внимание на object
Прошу извинить на поспешность.
← →
default © (2006-09-04 13:35) [21]atruhin © (04.09.06 12:32) [15]
открываем справку по Delphi, затем переходим на вкладу поиска по указателю, заносим в строку поиска абру "vmt" и читаем, там всё написано
также написано и
"The first 4-byte field of every object is a pointer to the virtual method table (VMT) of the class."
надо зырить на процент памяти, используемый на указатель на vmt, по сравнению с размером записи
4/SizeOf(TRecord)
на другую инфу можно забить ибо она хранится в единственном экземпляре
← →
atruhin © (2006-09-04 15:38) [22]> [16] oxffff © (04.09.06 12:42)
Ну дак а я о чем писал? Посмотри внимательнее.
> [21] default © (04.09.06 13:35)
Спасибо. Исчерпывающий ответ. Больше вопросов нет.
← →
oxffff © (2006-09-04 16:33) [23]to atruhin
oxffff © (04.09.06 12:47) [16]
oxffff © (04.09.06 12:47) [17]
Может вам стоит быть внимательнее
← →
oxffff © (2006-09-04 16:50) [24]to atruhin
class это не только VMT
Размер типа
VMT
+dynamic method table
+short string containing class name
+method definition table
+type information table
+instance initialization table
+Automation information table
+interface table
← →
zamtmn © (2006-09-05 10:16) [25]to oxffff
> Вы путаете это с С++
>
> Указатель на VMT всегда по нулевому смещению
Справедливо для class, у object VMT не всегда находится по нулеыому смещению, более того его может не быть вообще, если нет виртуальных методов
← →
zamtmn © (2006-09-05 10:21) [26]tobj1=object
field1,field2:intrger
end;
tobj2=object(tobject1)
field3:integer
procedure test;virtual;abstract;
end;
в памяти tobj1 будет выглядить - field1,field2
tobj2 - field1,field2,^VMT,field3
← →
oxffff © (2006-09-05 10:28) [27]to zamtmn
Полностью согласен с вами.
Когда постил
oxffff © (04.09.06 12:59) [19]
не обратил внимание на object.
В следующем посте извинился.
oxffff © (04.09.06 13:02) [20]
Просто к счастью не довелось работать с оbject.
Вчера достал у себя в закромах старую книгу и почитал.
Действительно указатель на VMT "плавающий".
← →
zamtmn © (2006-09-05 10:37) [28]to oxffff
а я в свою очередь незаметил Ваш пост [20]. извиняюсь
to atruhin
в случае использования
object
X, Y : integer;
constructor Create(aX,aY : integer);
end;
разницы не будет никакой до появления виртуальных методов
← →
oxffff © (2006-09-06 12:34) [29]to zamtmn ©
> разницы не будет никакой до появления виртуальных методов
Разница все таки будет.
Дело в том что для оbject все равно создается таблица VMT.
Где по -4 байт хранится смещение относительно начала экземпляра,
где хранится указатель на VMT.
Где по -8 байт хранится размер экземпляра.
Другое дело, если не объявлены виртуальные методы, тогда конструктор
просто не инициализирует в экземпляре указатель на VMT.
Но таблица VMT существовать будет.
← →
zamtmn © (2006-09-06 13:58) [30]>>Дело в том что для оbject все равно создается таблица VMT.
согласен, я имел ввиду разницу хранения в памяти экземпляра record и object. заголовок vmt всеравно будет создан для работы TypeOf, но он будет один для всех объектов данного типа
Страницы: 1 вся ветка
Форум: "Основная";
Текущий архив: 2006.10.15;
Скачать: [xml.tar.bz2];
Память: 0.54 MB
Время: 0.045 c