Я читаю в большом текстовом файле с 1,4 миллионами строк размером 24 МБ (в среднем 17 символов в строке).
Я использую Delphi 2009, файл ANSI, но при чтении он конвертируется в Unicode, поэтому, если честно, можно сказать, что размер преобразованного текста составляет 48 МБ.
(Изменить: я нашел гораздо более простой пример ...)
Я загружаю этот текст в простой StringList:
AllLines := TStringList.Create;
AllLines.LoadFromFile(Filename);
Я обнаружил, что строки данных, похоже, занимают гораздо больше памяти, чем их 48 МБ.
На самом деле они используют 155 МБ памяти.
Я не возражаю против использования Delphi 48 МБ или даже целых 60 МБ с учетом некоторых накладных расходов на управление памятью. Но 155 МБ кажется чрезмерным.
Это не ошибка StringList. Ранее я пытался загрузить строки в структуру записи, и я получил тот же результат (160 МБ).
Я не вижу и не понимаю, что может быть причиной того, что Delphi или менеджер памяти FastMM используют в 3 раза больше памяти, необходимой для хранения строк. Распределение кучи не может быть настолько неэффективным, не так ли?
Я отладил это и исследовал, насколько смог. Будем весьма благодарны за любые идеи относительно того, почему это может происходить, или за идеи, которые могут помочь мне сократить избыточное использование.
Примечание: я использую этот "меньший" файл в качестве примера. Я действительно пытаюсь загрузить файл объемом 320 МБ, но Delphi запрашивает более 2 ГБ ОЗУ и не хватает памяти из-за этого лишнего требования к строке.
Addenum: Марко Канту только что выпустил Белую книгу по Delphi и Unicode . Delphi 2009 увеличил накладные расходы на строку с 8 байтов до 12 байтов (плюс еще 4 для фактического указателя на строку). Дополнительные 16 байтов на строку 17x2 = 34 байта добавляют почти 50%. Но я вижу более 200% накладных расходов. Какими могут быть дополнительные 150%?
Успех !! Спасибо всем вам за ваши предложения. Вы все заставили меня задуматься. Но я должен отдать должное Яну Гойваэртсу за ответ, так как он спросил:
... почему вы используете TStringList? Должен ли файл действительно храниться в памяти в виде отдельных строк?
Это привело меня к решению, что вместо загрузки файла размером 24 МБ в виде StringList объемом 1,4 миллиона я могу сгруппировать строки в естественные группы, о которых знает моя программа. Это привело к загрузке 127 000 строк в список строк.
Теперь в каждой строке в среднем 190 символов вместо 17. В каждой строке StringList накладные расходы такие же, но теперь строк намного меньше.
Когда я применяю это к файлу 320 МБ, он больше не исчерпывает память и теперь загружает менее 1 ГБ ОЗУ. (И загрузка занимает всего около 10 секунд, что очень хорошо!)
Для анализа сгруппированных строк потребуется немного больше обработки, но это не должно быть заметно при обработке каждой группы в реальном времени.
(Если вам интересно, это программа по генеалогии, и это, возможно, последний шаг, который мне понадобился, чтобы она позволила загружать все данные о одном человеке в 32-битном адресном пространстве менее чем за 30 секунд. Таким образом, у меня все еще есть 20-секундный буфер для добавления индексов в данные, которые потребуются для отображения и редактирования данных.)