powered by simpleCommunicator - 2.0.61     © 2026 Programmizd 02
Целевая тема:
Создать новую тему:
Автор:
Закрыть
Цитировать
Форумы / Delphi [игнор отключен] [закрыт для гостей] / Статический массив неизвестной длины
32 сообщений из 32, показаны все 2 страниц
Статический массив неизвестной длины
    #39918378
Фотография _Vasilisk_
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Задача: нужен класс контейнер, который будет хранить до 5-6 элементов. Количество элементов известно на этапе компиляции.

Писать так
Код: pascal
1.
2.
3.
4.
5.
6.
7.
8.
9.
TContainer = class
  FChilds: array of TMyObject;
  constructor Create(ACount: Integer);
end;

constructor TContainer.Create(ACount: Integer);
begin
  SetLength(FChilds, ACount);
end;

не могу из-за жесткого ограничения по памяти (оверхед при выделении памяти для динамического массива, а контейнеров создается очень много). По этой же причине не нравится
Код: pascal
1.
GetMem(FChilds, ACount * SizeOf(TMyObject))



Сейчас делаю так
Код: pascal
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
TContainer1 = class
  FChild1: TMyObject;
end;

TContainer2 = class(TContainer1)
  FChild2: TMyObject;
end;
........
TContainer5 = class(TContainer4)
  FChild5: TMyObject;
end;

оверхеда нет вообще, но много кода.

Можно как-то подсократить?

Пытался так
Код: pascal
1.
2.
3.
TContainer<T> = class
  FChilds: array[0..SizeOf(T) - 1] of TMyObject;
end;

но компилятор не считает SizeOf(T) константой.

С уважением, Vasilisk
...
Рейтинг: 0 / 0
Статический массив неизвестной длины
    #39918384
Sinemurius
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Сколько контейнеров и сколько элементов в одном контейнере Вы максимально хотите создать ?
...
Рейтинг: 0 / 0
Статический массив неизвестной длины
    #39918398
Фотография Квейд
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
_Vasilisk_
Задача: нужен класс контейнер, который будет хранить до 5-6 элементов. Количество элементов известно на этапе компиляции.

Писать так
Код: pascal
1.
2.
3.
4.
5.
6.
7.
8.
9.
TContainer = class
  FChilds: array of TMyObject;
  constructor Create(ACount: Integer);
end;

constructor TContainer.Create(ACount: Integer);
begin
  SetLength(FChilds, ACount);
end;

не могу из-за жесткого ограничения по памяти (оверхед при выделении памяти для динамического массива, а контейнеров создается очень много). По этой же причине не нравится
Код: pascal
1.
GetMem(FChilds, ACount * SizeOf(TMyObject))



О каком оверхеде идет речь?
Код: pascal
1.
SetLength(FChilds, 1000);


выделит ~4 Кб памяти
...
Рейтинг: 0 / 0
Статический массив неизвестной длины
    #39918400
x1ca4064
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
_Vasilisk_,

Перекрыть NewInstance не рассматривали? Можно выделить чуть больше памяти и хранить там массив, оверхеда быть не должно.
...
Рейтинг: 0 / 0
Статический массив неизвестной длины
    #39918405
Kazantsev Alexey
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
x1ca4064
Перекрыть NewInstance не рассматривали? Можно выделить чуть больше памяти и хранить там массив, оверхеда быть не должно.

А потом, кто-нибудь станет использовать для объекта синхронизацию монитором...
...
Рейтинг: 0 / 0
Статический массив неизвестной длины
    #39918455
Василий 2
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Кмк, говорить об оверхеде и при этом применять классы-контейнеры, содержащие классы же - это странно. Но окей, допустим.
В таком случае можно, например, использовать нечто вроде:
Код: pascal
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
TBaseContainer = class
  property Item read Get write Put
end;

TContainer1 = class(TBaseContainer)
  FObj1
end;

TContainer2 = class(TBaseContainer)
  FObj1, FObj2
end;

...

function CreateContainer(Num: Integer): TBaseContainer;
begin
  case Num of
    1: Result := TContainer1.Create;
   ...
end;

Container := CreateContainer(3);



UPD А еще (для любителей проктостоматологии) размер объекта у класса вычисляется как
Код: pascal
1.
2.
3.
4.
class function TObject.InstanceSize: Longint;
begin
  Result := PInteger(PByte(Self) + vmtInstanceSize)^;
end;


соответственно известно что делать
...
Рейтинг: 0 / 0
Статический массив неизвестной длины
    #39918461
rgreat
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Перейдете с классов на пакед рекорды - сэкономите память.
...
Рейтинг: 0 / 0
Статический массив неизвестной длины
    #39918473
Василий 2
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Вообще, если говорить о затратах памяти, любой объект изначально уже тратит больше 100 байт только на х32 (vmtCreateObject - vmtSelfPtr). Это еще не считая оверхеда менеджера памяти и своих виртуальных методов и не говоря про х64. Короче, классы - это не вариант, если нужно экономить память
...
Рейтинг: 0 / 0
Статический массив неизвестной длины
    #39918477
Kazantsev Alexey
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Василий 2
Вообще, если говорить о затратах памяти, любой объект изначально уже тратит больше 100 байт только на х32

Да ты гонишь. Объект минимум - 4 байта - ссылка на VMT класса.
...
Рейтинг: 0 / 0
Статический массив неизвестной длины
    #39918491
Kazantsev Alexey
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Kazantsev Alexey
Объект минимум - 4 байта

Сам себя поправлю, таки 8 байт. В размер включается ссылка на монитор. Соответственно, ничего страшного не случится даже если 22066064 .
...
Рейтинг: 0 / 0
Статический массив неизвестной длины
    #39918493
Фотография _Vasilisk_
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Sinemurius
Сколько контейнеров
Много. Несколько сотен. Может тысяча
Sinemurius
и сколько элементов в одном контейнере Вы максимально хотите создать ?
Не более 4. Ну может где-то появится с 5
Квейд
О каком оверхеде идет речь?
Код: pascal
1.
SetLength(FChilds, 1000);


выделит ~4 Кб памяти
Код: pascal
1.
SetLength(FChilds, 2)

выделит 8 байт на сам массив + 8 байт на это
Код: pascal
1.
2.
3.
4.
5.
6.
7.
  TDynArrayRec = packed record
  {$IFDEF CPUX64}
    _Padding: LongInt; // Make 16 byte align for payload..
  {$ENDIF}
    RefCnt: LongInt;
    Length: NativeInt;
  end;

итого оверхед 50%
x1ca4064
Перекрыть NewInstance не рассматривали?
Так, мысль интересная. Нужно подумать.

Kazantsev Alexey
А потом, кто-нибудь станет использовать для объекта синхронизацию монитором...
И в чем противопоказания?

Василий 2
В таком случае можно, например, использовать нечто вроде
Вы исходный вопрос читали? Именно от этого варианта и хочется уйти
...
Рейтинг: 0 / 0
Статический массив неизвестной длины
    #39918494
Фотография _Vasilisk_
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
x1ca4064
Перекрыть NewInstance не рассматривали?
А как туда передать размер?
...
Рейтинг: 0 / 0
Статический массив неизвестной длины
    #39918500
Kazantsev Alexey
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
_Vasilisk_
И в чем противопоказания?

Да уже ни в чём. InstanceSize возвращает размер с учётом ссылки на монитор.
...
Рейтинг: 0 / 0
Статический массив неизвестной длины
    #39918501
Kazantsev Alexey
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
_Vasilisk_
Много. Несколько сотен. Может тысяча

Эм... Это из-за 4-8 KB такая заморока???
...
Рейтинг: 0 / 0
Статический массив неизвестной длины
    #39918511
Фотография _Vasilisk_
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Kazantsev Alexey
Эм... Это из-за 4-8 KB такая заморока???
Нет. Почему-то отжирается памяти на порядок больше, чем общий размер объектов.

Создается тысячи мелких объектов (InstanceSize < 100 байт) и у системы отжирается 100 мегабайт. Создание этих объектов для 10 владельцев и OutOfMemory. Сейчас после базового рефракторинга удалось сократить базовое выделение до 20 мегабайт.

Где-то FastMM чудит и забирает у системы память сильно про запас
...
Рейтинг: 0 / 0
Статический массив неизвестной длины
    #39918522
Kazantsev Alexey
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
_Vasilisk_
Где-то FastMM чудит и забирает у системы память сильно про запас

Посмотри демку Usage Tracker. Она даёт полную картину выделения памяти, размеры блоков, степень оверхеда.
...
Рейтинг: 0 / 0
Статический массив неизвестной длины
    #39918524
DmSer
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Василий 2
Вообще, если говорить о затратах памяти, любой объект изначально уже тратит больше 100 байт только на х32 (vmtCreateObject - vmtSelfPtr). Это еще не считая оверхеда менеджера памяти и своих виртуальных методов и не говоря про х64. Короче, классы - это не вариант, если нужно экономить память


проверил. Что TObject.Create, что New(pInteger) занимают 16 байт (даже в x64). Видимо, для TObject там только указатель на VMT и резервный указатель на Monitor.
...
Рейтинг: 0 / 0
Статический массив неизвестной длины
    #39918533
Kazantsev Alexey
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Вот Usage Tracker. Можно посмотреть какие реальные размеры блоков использует менеджер. Например, при выделении 13 байт реально выделяется 20 из пула размером 29488. P.S. Данные для XE2, на более поздних они могут отличаться. P.P.S. Проверил в 10.3 - размеры те же.
...
Рейтинг: 0 / 0
Статический массив неизвестной длины
    #39918540
Kazantsev Alexey
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
10.3
...
Рейтинг: 0 / 0
Статический массив неизвестной длины
    #39918549
Фотография _Vasilisk_
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Kazantsev Alexey
Посмотри демку Usage Tracker.
Где ее брать?
...
Рейтинг: 0 / 0
Статический массив неизвестной длины
    #39918551
Kazantsev Alexey
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
_Vasilisk_
Где ее брать?

Стандартная демка дельфийская. Правда с какой-то версии её перестали поставлять, но в XE2 она точно есть. Может есть в их репе с демками.
...
Рейтинг: 0 / 0
Статический массив неизвестной длины
    #39918553
Kazantsev Alexey
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Нашёл . XE6 последняя, где эта демка была.
...
Рейтинг: 0 / 0
Статический массив неизвестной длины
    #39918585
x1ca4064
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
_Vasilisk_
x1ca4064
Перекрыть NewInstance не рассматривали?
А как туда передать размер?


Я бы делал через
Код: sql
1.
class function InternalArrayLength:integer; virtual;


соответственно для разных TContainer1..5 возвращал кол-во элементов массива, хотя можно и через какой-нибудь threadvar, но это как-то не так
...
Рейтинг: 0 / 0
Статический массив неизвестной длины
    #39918587
alekcvp
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Что мешает сделать статический массив максимального требуемого размера и использовать только нужную его часть?
Накладные расходы - пара лишних байт, тут уж точно никакого перерасхода памяти не будет.
...
Рейтинг: 0 / 0
Статический массив неизвестной длины
    #39918600
ёёёёё
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
alekcvp,

Зашибись, типа собственный менеджер памяти давай напишем.
...
Рейтинг: 0 / 0
Статический массив неизвестной длины
    #39918601
alekcvp
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
ёёёёё
alekcvp,
Зашибись, типа собственный менеджер памяти давай напишем.

Ну если у него действительно стопиццоттыщ массивчиков по 5-6 элементов, то динамические массивы реально дают большие накладные расходы: сначала минимальный размер блока в менеджере памяти, потом заголовок блока в менеджере памяти (размер хз), потом префикс динамического массива (8 байт вроде), т.е. ради 20-24 байт данных сверху может набежать ещё дохрена (+ выравнивание). А в моём варианте - нужна только одна переменная, размером в байт, содержащая используемый размер массива. И статические массивы никаких накладных расходов не несут.

Можно вообще изобрести заново shortstring: двумерный статический массив, в каждой строке которого 0й элемент - размер данных в этой строке :)
...
Рейтинг: 0 / 0
Статический массив неизвестной длины
    #39918602
Kazantsev Alexey
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
ёёёёё
Зашибись, типа собственный менеджер памяти давай напишем.

Мысль, на самом деле, здравая. У ТС в контейнере максимум 6 элементов. Даже если храниться будет только 1, то оверхед составит всего 20/40 байт. Таких контейнеров у него около тысячи, итого максимальный оверхед 20/40 KB. Какая-то непонятная попытка экономить на спичках.
...
Рейтинг: 0 / 0
Статический массив неизвестной длины
    #39918604
ёёёёё
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Kazantsev Alexey
Мысль, на самом деле, здравая. У ТС в контейнере максимум

Темнит ТС что-то.
...
Рейтинг: 0 / 0
Статический массив неизвестной длины
    #39918608
rgreat
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
ёёёёё
Темнит ТС что-то.
+100500.

Не поленился написать тест.

Код: pascal
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
type
  TMyObject = TObject;

  TContainer = class
    FChilds: array of TMyObject;
    constructor Create(ACount: Integer);
  end;


procedure TForm13.Button1Click(Sender: TObject);
var
  I         : Integer;
  Container : TContainer;
begin
  for I:=0 to 1000 do begin
    TContainer.Create(random(5)+1);
  end;
end;

{ TContainer }

constructor TContainer.Create(ACount: Integer);
var
  I: Integer;
begin
  SetLength(FChilds, ACount);
  for I :=0 to ACount-1 do begin
    FChilds[i]:=TMyObject.Create;
  end;
end;


Создание 1000 контейнеров с 1-5 детьми каждый "сжирает" менее 100 кб памяти.

В общем доблестный инспектор Лестрейд уверенно пошел по ложному следу.

Откуда у него там десятки мегабайт - тайна скрытая мраком.
Либо у него все жрет TMyObject либо утечки где-то еще.
...
Рейтинг: 0 / 0
Статический массив неизвестной длины
    #39918974
Василий 2
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Kazantsev Alexey
Да ты гонишь. Объект минимум - 4 байта - ссылка на VMT класса.

Блин, точно. Ориентировался на код типа PInteger(PByte(Self) + vmtInstanceSize)^, но упустил из виду, что это метод класса, то есть Self там это TObject.

_Vasilisk_
Вы исходный вопрос читали? Именно от этого варианта и хочется уйти

Во-первых, это совсем не тот вариант, что в исходном вопросе, а во-вторых, какое изложение (кривое) - такой и ответ.
...
Рейтинг: 0 / 0
Статический массив неизвестной длины
    #39921464
DmSer
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
DmSer
Василий 2
Вообще, если говорить о затратах памяти, любой объект изначально уже тратит больше 100 байт только на х32 (vmtCreateObject - vmtSelfPtr). Это еще не считая оверхеда менеджера памяти и своих виртуальных методов и не говоря про х64. Короче, классы - это не вариант, если нужно экономить память


проверил. Что TObject.Create, что New(pInteger) занимают 16 байт (даже в x64). Видимо, для TObject там только указатель на VMT и резервный указатель на Monitor.


У каждого блока оказывается есть ещё заголовок размером NativeUInt
...
Рейтинг: 0 / 0
Статический массив неизвестной длины
    #39921475
Sinemurius
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Я не читал конечно ТЗ, но субъективно очень смахивает на то, что Вам нужна работа с базой данных.
...
Рейтинг: 0 / 0
32 сообщений из 32, показаны все 2 страниц
Форумы / Delphi [игнор отключен] [закрыт для гостей] / Статический массив неизвестной длины
Найденые пользователи ...
Разблокировать пользователей ...
Читали форум (0):
Пользователи онлайн (0):
x
x
Закрыть


Просмотр
0 / 0
Close
Debug Console [Select Text]