Аналог TStringList для записей

Вопросы программирования и использования среды Lazarus.

Модератор: Модераторы

Аватара пользователя
VirtUX
энтузиаст
Сообщения: 880
Зарегистрирован: 05.02.2008 09:52:19
Откуда: Крым, Алушта

Сообщение VirtUX »

svk12 писал(а):И вставляйте его в TStringList.

VirtUX писал(а):Создавать целые объекты для миллионов параметров AnyParam мне кажется ресурсозатратным для ОЗУ.

Вот сколько будет выделено памяти под TPointerStore? Я так понимаю, что память будет занята всеми его полями, которые мне не нужны. И ОЗУ будет хранить более 50% всякого не нужного мусора. Или я не правильно понимаю выделение памяти под новый экземпляр TObject?

Добавлено спустя 20 минут 11 секунд:
Например: имеем 1 миллиард параметров. каждый параметр имеет идентификатор длиной в 10 байт (например: 'а000000001'). Параметр занимает в памяти 12 байт

Код: Выделить всё

ParamForExample = record
pos: int64;
offset: DWord;
end;

Если использовать Pointer, то под каждый параметр будет использовано 12 + 4 (32bit) или 12 + 8 (64bit) байт в ОЗУ. А сколько будет использовано под класс, включающий в себя эти 16 или 20 байт? И умножим это на 1 миллиард. Сколько будет не нужного мусора в ОЗУ? Сколько занимает памяти сам TObject?
32 Гб ОЗУ под параметры мне сейчас не проблема выделить. Но если больше, то придется свопироваться, или разбивать на страницы. Но тогда теряем производительность.
svk12
постоялец
Сообщения: 411
Зарегистрирован: 09.06.2008 18:42:47

Сообщение svk12 »

VirtUX писал(а):Сколько занимает памяти сам TObject?


Адрес VMT - 4 или 8 байт (32/64).
Аватара пользователя
VirtUX
энтузиаст
Сообщения: 880
Зарегистрирован: 05.02.2008 09:52:19
Откуда: Крым, Алушта

Сообщение VirtUX »

Эксперимент проводится на openSuSE 13.1 32bit, Lazarus 1.0.14, FPC 2.6.2
===========
Странный эффект (наблюдаю в списке процессов KDE 4.11.5):
Типы:

Код: Выделить всё

type
re = record
i: int64;
d: dword;
end;
pre = ^re;
tre = class
  f: re;
end;

Если запустить так:

Код: Выделить всё

var
a: array [1 .. $FFFFFF] of TObject;
...
var
  i: DWord;
begin
  for i := 1 to $FFFFFF do a[i] := TObject.Create;

то занимаемая память ~334 Mb
если так:

Код: Выделить всё

var
a: array [1 .. $FFFFFF] of tre;
...
var
  i: DWord;
begin
  for i := 1 to $FFFFFF do a[i] := tre.Create;

то занимаемая память ~597 Mb, что логично. Т.к. добавились ~268 Mb данных (re)
Теперь так:

Код: Выделить всё

var
a: array [1 .. $FFFFFF] of re;
...
var
  i: DWord;
begin
  for i := 1 to $FFFFFF do a[i].d :=i ;

и занимаемая память ~ 268 Mb - все отлично, как и должно быть. Но теперь:

Код: Выделить всё

var
a: array [1 .. $FFFFFF] of pre;
...
var
  i: DWord;
begin
  for i := 1 to $FFFFFF do new(a[i]);

и память снова ~597 Mb!!! С чего это?.. Дополнительно ~19 байт на каждую запись.
Если так:

Код: Выделить всё

type
re = record
i: int64;
d: dword;
end;
pre = ^re;
tre = class
  f: pre;
end;
...
var
a: array [1 .. $FFFFFF] of tre;
...
var
  i: DWord;
begin
  for i := 1 to $FFFFFF do begin
  a[i] := tre.Create;
  new(a[i].f);

то все ~859 Mb.

Где-то я читал, что чистый TObject занимает ~20 байт. Получается: хоть Pointer используй, хоть TObject - все одно к каждой записи + 20 байт. Я правильно понимаю?
zub
долгожитель
Сообщения: 2889
Зарегистрирован: 14.11.2005 22:51:26
Контактная информация:

Сообщение zub »

VirtUX
>>Где бы взять такой TStringList, имеющий возможность хранить просто Pointer вместо TObject? Или как обмануть TStringList?
Кто мешает подсунуть Pointer вместо TObject в обычный TStringList? переменная TObject по сути это обычный указатель

>>Сколько занимает памяти сам TObject?
посмотрите что вернет TObject.InstanceSize. насколько помню должно быть sizeof(pointer) - указатель на описание класса - структуру данных TVMT.
т.е.

Код: Выделить всё

var
  MyClass:tobject;
...
  MyClass:=TObject.Create
...

в результате в MyClass будет указатель на sizeof(pointer) байт в куче, а в этих байтах будет указатель на TVMT TObject`а

Массив классов грубо говоря это массив указателей и если вы собираетесь хранить миллиард "чегото там" - классы плохое решение, особенно если "чегото там" это небольшие данные:
-доступ через указатели=хранение ненужных указателей при индексном доступе
-накладные расходы "лишнего" TObject.InstanceSize
-невозможность выделить память под всё сразу=отдельное выделение под каждый экземпляр
Для мелочи имхо лучше использовать обьекты или рекорды

>>Есть массив параметров типа record. Есть список строковых идентификаторов для этого массива параметров. Сейчас это выглядит в двух вариантах:
Поглядите gmap из fpc-stl телепатор подсказывает что это именно то что вам надо
Аватара пользователя
VirtUX
энтузиаст
Сообщения: 880
Зарегистрирован: 05.02.2008 09:52:19
Откуда: Крым, Алушта

Сообщение VirtUX »

gmap из fcl-stl не имеет встроенной сортировки и прочих вкусностей TStringList.
zub писал(а):Кто мешает подсунуть Pointer вместо TObject в обычный TStringList?

Мистика :) Вчера вываливалось с ошибкой. Сегодня переустановил Лазаря. Ничего не менял в конфах, проектах. Ну... совсем ничего не менял, и... сегодня проглотило :)

Код: Выделить всё

procedure TForm1.Button1Click(Sender: TObject);
type
  ro = record
    i: int64;
    d: DWord;
  end;
  pro = ^ro;

var
  sl: TStringList;
  i: DWord;
begin

  sl := TStringList.Create;

    for i := 0 to $FFFFFF
    do begin
      sl.AddObject('', TObject(GetMem(SizeOf(ro))));
      pro(sl.Objects[i])^.d:= i;
      pro(sl.Objects[i])^.i:= i;
    end;

  // Деструкция в другой процедуре

end;

Мой вопрос закрыт
Ответить