Top.Mail.Ru
Мастера DELPHI, Delphi programming community Титульная страница Поиск, карта сайта Написать письмо 
| Новости | Поиск | FAQ | Статьи | Книги | Новости VCL |
| Форумы ЧАТ | Орешник | KOL и MCK |
Форумы -» Основная («Начинающим»)/ Базы / WinAPI / Компоненты / Сети / Media / Игры / Corba и COM / KOL / FreePascal / .Net / Прочее / RSDN.ORG

« предыдущая ветвь | форум | следующая ветвь »

Копируется ли строка про добавлении в ListBox или нет ? [D7, Win2k, WinXP]


Альф ©   (2007-01-24 10:43:00) 

Есть массив строк

var
 astr: array of string;

необходимо это массив визуализировать - например вывести в ListBox.

Вопрос - будет ли дублироваться в памяти каждая строка при добавлении из массива строк в ListBox.Items ?
Или же физически строка в памяти будет одна - а в ListBox.Items будет только ссылка на неё ?


Игорь Шевченко   (2007-01-24 17:35:00) [1]

Альф   (24.01.07 15:05) [15]

Разумеется, строки переводятся в Unicode, если ListBox их хранит
Но зачем отображать в listBox 65 тысяч строк в стандартном режиме - мания такая, да ? Пусть нашим пользователям будет хуже ?


Альф   (2007-01-24 15:05:00) [2]

Большое спасибо всем кто учавствовал в обсуждении.

Сделал небольшой пример, на котором видно что памяти используется гораздо больше чем нужно было бы.

Шаг 1:
Запускаем програмку.
Размер виртуальной памяти процесса в диспетчере задач = 848К

Шаг 2:
Вызываем эту процедуру -  размер памяти = 7 240К

var
 astr: array of string;

procedure T_main.Button5Click(Sender: TObject);
const
 S_1 = ' - Просто досточно длинная строка символов для проверки алгоритма работы';
var
 i: integer;
begin
 Button5.Enabled := false;
 SetLength(astr, High(word));
 for i := Low(astr) to High(astr) do begin
   astr[i] := IntToStr(i) + S_1 + IntToStr(Random(i));
 end;
 Sleep(500);
 Button5.Enabled := true;
end;


Проверяем на калькуляторе примерный размер: 90*65534 =  около 6М.
Не точно - но очень похоже.

Шаг 2:
Заполняем ListBox1.
Процедура выполняется достаточно долго - результирующий размер памяти = 19 860К :(
Прирост еще в 12М ??? Судя по всему - или добавляется две копии - или же все строки переводяться в Unicode.


procedure T_main.Button6Click(Sender: TObject);
var
 i: integer;
begin
 Button6.Enabled := false;
 ListBox1.Items.BeginUpdate();
 for i := Low(astr) to High(astr) do begin
   ListBox1.Items.Add(astr[i]);
 end;
 ListBox1.Items.EndUpdate();
 Sleep(500);
 Button6.Enabled := true;
end;


Еще раз повторюсь - процедура работает в несколько раз дольше чем первая.

Шаг 3:
Чистим ListBox

 ListBox1.Clear();
 
Размер виртуалки практически возвратился к исходному и = 7 304К


Rouse_   (2007-01-24 13:56:00) [3]

Вот если стиль стоит lbVirtual у listBox, тогда все нормально все три ShowMessage показывают наличие пробелов. По умолчанию же стоит стиль lbStandard, который именно копирует


Игорь Шевченко   (2007-01-24 13:52:00) [4]

Rouse_ ©   (24.01.07 13:40) [12]

Теперь попробоуй свой код с ListBox, у которого стиль позволяет хранить пользовательские строки. Интересно.


Rouse_   (2007-01-24 13:40:00) [5]

1. добавляем строки в ListBox
2. присваиваем строку другой переменной (в этот момент они указывают на один и тот же буффер)
3. пишем в этот буффер пробелы, чтобы небыло вызова UniqueStr
4. проверяем - обе переменных читающие с этого буффера показывают наличие пробелов
5. еслибы в listBox были тоже указатели, то последний ShowMessage(S) показал бытоже, что и ShowMessage(A)
6. А показывается полная строка.
7. вопрос, откуда берется эта полная оригинальная строка, если буффер. который ее хранил затерт пробелами...?


Игорь Шевченко   (2007-01-24 13:37:00) [6]

Rouse_ ©   (24.01.07 13:16) [10]

А чего твой код-то показывает ?


Rouse_   (2007-01-24 13:16:00) [7]

Даже вот так лучше и наглядней:

procedure TForm24.Button1Click(Sender: TObject);
var
 i, d: integer;
 S, A: String;
begin
 S :=  'Просто достточно длинная строка символов для проверки алгоритмя работы' + IntToStr(GetTickCount);
 for i := 0 to 3000 do
   ListBox1.Items.Add(S);
 d := 32;
 A := S;
 for i := 0 to 69 do
   Move(d, Pointer(DWORD(Pointer(S)) + I)^, 1);
 ShowMessage(S);
 ShowMessage(A);
 S := ListBox1.Items.Strings[1];
 ShowMessage(S);
end;


Rouse_   (2007-01-24 13:14:00) [8]

Проверка №2, для неверующих:

procedure TForm24.Button1Click(Sender: TObject);
var
 i, d: integer;
 S: String;
begin
 S :=  'Просто достточно длинная строка символов для проверки алгоритмя работы' + IntToStr(GetTickCount);
 for i := 0 to 3000 do
   ListBox1.Items.Add(S);
 d := 32;
 for i := 0 to 69 do
   Move(d, Pointer(DWORD(Pointer(S)) + I)^, 1);
 ShowMessage(S);
 S := ListBox1.Items.Strings[1];
 ShowMessage(S);
end;


Rouse_   (2007-01-24 13:09:00) [9]


> А ты подумай, с чего ей дублироваться ?


> то есть, он копирует строки к себе?

Да копирует, для оптимизации добавления большого кол-ва строк есть даже сообщение LB_INITSTORAGE


clickmaker   (2007-01-24 12:52:00) [10]

хотя...
LBS_HASSTRINGS
Specifies that a list box contains items consisting of strings. The list box maintains the memoryand addresses for the strings

то есть, он копирует строки к себе?
тогда дубль, да


clickmaker   (2007-01-24 12:43:00) [11]


> [4] Rouse_ ©   (24.01.07 11:58)

lParam
Pointer to the null-terminated string that is to be added.
If you create the list box with an owner-drawn style but without the LBS_HASSTRINGS style, this parameter is stored as item data instead of the string to which it would otherwise point

указатель это. Откуда там возьмется дубль?


Игорь Шевченко   (2007-01-24 12:38:00) [12]

Rouse_ ©   (24.01.07 11:58) [4]

А ты подумай, с чего ей дублироваться ?


Rouse_   (2007-01-24 11:58:00) [13]


> Не будет дублироваться

Да? Хм...

function TListBoxStrings.Add(const S: string): Integer;
begin
 Result := -1;
 if ListBox.Style in [lbVirtual, lbVirtualOwnerDraw] then exit;
  Result := SendMessage(ListBox.Handle, LB_ADDSTRING, 0, Longint(PChar(S)));
 if Result < 0 then raise EOutOfResources.Create(SInsertLineError);
end;


Проверка:
procedure TForm24.Button1Click(Sender: TObject);
var
 i: integer;
 S, A, B, C: String;
begin
 S :=  'Просто достточно длинная строка символов для проверки алгоритмя работы' + IntToStr(GetTickCount);
 for i := 0 to 3000 do
   ListBox1.Items.Add(S);
 A := S;
 B := S;
 C := S;
 ShowMessage(IntToStr(DWORD(Pointer(DWORD(Pointer(S)) - 8)^)));
end;


Что и требовалось доказать :)


Игорь Шевченко   (2007-01-24 11:20:00) [14]

Rouse_ ©   (24.01.07 10:45) [1]

Не будет дублироваться


TRUNK   (2007-01-24 11:01:00) [15]

По идее для строк применяется правило CopyOnWrite, т.е. при простом копировании строки происходит только копирование указателя, а уже при попытке изменения скопированной строки происходит создание второй строки с другим указателем.


Rouse_   (2007-01-24 10:45:00) [16]

Будет дублироваться...


Наверх

Титульная страница Поиск, карта сайта Написать письмо