Многие классы, у которых есть список элементов, имеют свойство "Capacity" или его аналог. Можно всю жизнь программировать и не догадываться о его существовании. Но оно есть. Так зачем оно нужно и как его использовать?
Каждое добавление нового элемента в список, приведет к перераспределению памяти, которая выделена под массив элементов этого списка. Когда элементов не много - это не важно, но когда их много, постоянное перераспределение памяти может замедлить вашу программу.
Что бы избежать перераспределения памяти при добавлении нового элемента в список и необходимо свойство Capacity. Оно позволяет заранее распределить память под массив элементов и тем самым повысить производительность программы. Проведем небольшой тест:
Как вы видите, предварительное распределение памяти под массив элементов списка дает существенное увеличение производительности.
Если количество элементов точно не известно, то можно распределить память под какое-то приблизительное количество элементов. Если список будет заполнен до предела, то свойство Capacity при добавлении нового элемента увеличивается автоматически. Подобное увеличение свойства Capacity можно сделать и "руками" вызвав метод Expand, который, если список заполнен, сам рассчитает новое значение Capacity. Для использованного в моем примере TList<integer> автоматическое расширение Capacity увеличивает его значение на 50% уже начиная с Capacity=66. Поэтому, при миллионах элементов можно распределить много лишней памяти или даже поймать "Out of memory". Значит свойство Capacity лучше контролировать самому и увеличивать его с определенным шагом. Например:
Таким образом, знать о свойстве Capacity и уметь с ним работать может быть весьма полезно.
Каждое добавление нового элемента в список, приведет к перераспределению памяти, которая выделена под массив элементов этого списка. Когда элементов не много - это не важно, но когда их много, постоянное перераспределение памяти может замедлить вашу программу.
Что бы избежать перераспределения памяти при добавлении нового элемента в список и необходимо свойство Capacity. Оно позволяет заранее распределить память под массив элементов и тем самым повысить производительность программы. Проведем небольшой тест:
Результаты:uses System.Classes, System.SysUtils, System.Generics.Collections, System.Diagnostics; const ciCount = 1000000; procedure CapacityTest; var l: TList<integer>; sw: TStopwatch; i, j: integer; begin sw := TStopwatch.StartNew; for j := 1 to 10 do begin l := TList<integer>.Create; try for i := 1 to ciCount do l.Add(i); finally l.Free; end; end; sw.Stop; WriteLn(FormatFloat('0.0', sw.ElapsedMilliseconds / 10)); sw := TStopwatch.StartNew; for j := 1 to 10 do begin l := TList<integer>.Create; l.Capacity := ciCount; try for i := 1 to ciCount do l.Add(i); finally l.Free; end; end; sw.Stop; WriteLn(FormatFloat('0.0', sw.ElapsedMilliseconds / 10)); end;
Количество элементов | Разрядность программы, бит | Время без Capacity, мс | Время с Capacity, мс | Прирост скорости, % |
1 000 000 | 32 | 5,2 | 3,0 | 42,31 |
1 000 000 | 64 | 5,1 | 3,2 | 37,26 |
10 000 000 | 32 | 59,2 | 31,5 | 46,79 |
10 000 000 | 64 | 61,4 | 34,9 | 43,16 |
10 0000 000 | 32 | 528,8 | 323,1 | 38,90 |
10 0000 000 | 64 | 525,6 | 350,8 | 33,26 |
Если количество элементов точно не известно, то можно распределить память под какое-то приблизительное количество элементов. Если список будет заполнен до предела, то свойство Capacity при добавлении нового элемента увеличивается автоматически. Подобное увеличение свойства Capacity можно сделать и "руками" вызвав метод Expand, который, если список заполнен, сам рассчитает новое значение Capacity. Для использованного в моем примере TList<integer> автоматическое расширение Capacity увеличивает его значение на 50% уже начиная с Capacity=66. Поэтому, при миллионах элементов можно распределить много лишней памяти или даже поймать "Out of memory". Значит свойство Capacity лучше контролировать самому и увеличивать его с определенным шагом. Например:
Если вы добавили все элементы в список, а их количество оказалось меньше, чем Capacity, то не используемую память необходимо освободить с помощью присвоения свойству Capacity значения свойства Count:l.Capacity := l.Capacity + 1000000;
или можно вызвать реализующий это присвоение inline-метод TrimExcess.l.Capacity := l.Count;
Таким образом, знать о свойстве Capacity и уметь с ним работать может быть весьма полезно.
Комментариев нет:
Отправить комментарий