Почему SetString занимает меньше памяти в Delphi (с Unicode)? - PullRequest
8 голосов
/ 25 сентября 2010

Это Delphi 2009, поэтому применяется Unicode.

У меня был код, который загружал строки из буфера в StringList следующим образом:

      var Buffer: TBytes; RecStart, RecEnd: PChar; S: string;

      FileStream.Read(Buffer[0], Size);

      repeat
         ... find next record RecStart and RecEnd that point into the buffer;        

         SetString(S, RecStart, RecEnd - RecStart);
         MyStringList.Add(S);
      until end of buffer

Но во время некоторых модификаций яизменил мою логику так, чтобы в итоге я добавил идентичные записи, но в виде строк, полученных отдельно, а не через SetString, т.е.

      var SRecord: string;

      repeat
        SRecord := '';
        repeat
          SRecord := SRecord + ... processed line from the buffer;
        until end of record in the buffer

        MyStringList.Add(SRecord);
      until end of buffer

Что я заметил, так это то, что использование памяти StringList возросло с 52 МБ дооколо 70 МБ.Это было увеличение более чем на 30%.

Чтобы вернуться к более низкому использованию памяти, я обнаружил, что мне нужно было использовать SetString для создания строковой переменной для добавления в мой StringList следующим образом:

      repeat
        SRecord := '';
        repeat
          SRecord := SRecord + ... processed line from the buffer;
        until end of record in the buffer

        SetString(S, PChar(SRecord), length(SRecord));
        MyStringList.Add(S);
      until end of buffer

Проверка и сравнение S и SRecordво всех случаях они абсолютно одинаковы.Но добавление SRecord в MyStringList использует гораздо больше памяти, чем добавление S.

Кто-нибудь знает, что происходит и почему SetString экономит память?


Followup.Я не думал, что это произойдет, но я проверил, чтобы убедиться.

Ни:

  SetLength(SRecord, length(SRecord));

, ни

  Trim(SRecord);

освобождает лишнее пространствоКажется, для этого требуется SetString.

Ответы [ 2 ]

15 голосов
/ 26 сентября 2010

Если вы объедините строку, менеджер памяти выделит больше памяти, поскольку он предполагает, что вы добавляете в нее все больше и больше текста, и выделяет дополнительное пространство для будущих объединений.Таким образом, размер выделения строки намного больше используемого размера (в зависимости от используемого менеджера памяти).Если вы используете SetString, размер выделения новой строки почти совпадает с используемым размером.И когда строка SRecord выходит из области видимости и ее ref-count становится равным нулю, память, занятая SRecord, освобождается.Таким образом, вы получите наименьший необходимый размер выделения для вашей строки.

0 голосов
/ 26 сентября 2010

Попробуйте установить фильтр диспетчера памяти (Get / SetMemoryManager), который передает все вызовы GetMem / FreeMem в диспетчер памяти по умолчанию, но также выполняет сбор статистики.Вы, вероятно, увидите, что оба варианта одинаковы по потреблению памяти.

Это просто фрагментация памяти.

...