В чем разница между GetMem и AllocMem? - PullRequest
0 голосов
/ 21 мая 2019

В Delphi я вижу несколько похожих функций, которые можно использовать для выделения памяти, например, GetMem и AllocMem.В чем различия между ними?

Я прочитал документ и обнаружил, что GetMem не будет инициализировать память после выделения, в то время как AllocMem делает.

Тогда нужно ли мне инициализировать память после вызоваGetMem?Док говорит да.Но я вижу в некоторых исходных кодах Delphi они не вызывают Initialize.

И нужно ли мне завершать память после ее использования?Я вижу в некоторых исходных кодах Delphi, они делают, но кое-что они не делают.

Спасибо

Ответы [ 3 ]

6 голосов
/ 21 мая 2019

Логика кажется простой - если вам нужен буфер с нулевой инициализацией, вы можете использовать AllocMem.

Если вы в любом случае заполняете буфер собственными данными и никогда не используете содержимое по умолчанию - вы можете использовать GetMem.

5 голосов
/ 21 мая 2019

Разница в том, что AllocMem заполняет новый выделенный буфер нулями, а GetMem - нет. Если ваш код требует, чтобы вновь выделенный буфер изначально был полностью нулем, вы можете использовать AllocMem вместо ручной записи нулей в буфер; если вам не нужны начальные байты в буфере, вы можете сделать (вероятно) дешевле GetMem.

Например,

var
  p: PByte;
begin
  GetMem(p, 1024);
  try
    p^ := 20;
    (p + 1)^ := 30;
    (p + 2)^ := p^ + (p + 1)^;
    ShowMessage((p + 2)^.ToString);
  finally
    FreeMem(p);
  end;
end;

действителен и всегда будет отображать 50, но

GetMem(p, 1024);
try
  p^ := 20;
  (p + 2)^ := p^ + (p + 1)^;
  ShowMessage((p + 2)^.ToString);
finally
  FreeMem(p);
end;

может отображать что угодно - все зависит от того, какой байт был в p + 1 во время выполнения кода (случайность).

Если вы начнете с заполнения буфера нулями, как в

GetMem(p, 1024);
try
  FillChar(p^, 1024, 0);
  p^ := 20;
  (p + 2)^ := p^ + (p + 1)^;
  ShowMessage((p + 2)^.ToString);
finally
  FreeMem(p);
end;

вы гарантированно увидите 20, поскольку p + 1 будет удерживать 0.

В качестве альтернативы вы можете сделать

p := AllocMem(1024);
try
  p^ := 20;
  (p + 2)^ := p^ + (p + 1)^;
  ShowMessage((p + 2)^.ToString);
finally
  FreeMem(p);
end;

, поскольку документация гарантирует, что AllocMem устанавливает каждый байт во вновь выделенном буфере на 0.

Но, конечно, выделение памяти вручную в куче предназначено для ("продвинутых") вещей низкого уровня; чаще всего вы этого не делаете. Если вы это сделаете, вы должны знать о таких вещах, как внутренние форматы данных .

1 голос
/ 21 мая 2019

Зависит от вашей потребности. Вам нужен только буфер, и вам все равно, что у него изначально? Используйте GetMem.

GetMem выделяет блок заданного размера в куче и возвращает адрес этой памяти в параметре P. Байты выделенного буфер не установлен на ноль. Чтобы избавиться от буфера, используйте FreeMem. Если недостаточно места для выделения блока, Возникла исключительная ситуация EOutOfMemory.

Примечание: если память должна быть инициализирована нулями, используйте AllocMem вместо этого.

Если ваша логика ожидает, что все байты этого буфера установлены в ноль, используйте AllocMem.

AllocMem выделяет блок заданного размера в куче и возвращает адрес этой памяти. Каждый байт в выделенном буфере установлен в ноль. Чтобы избавиться от буфера, используйте FreeMem. Если не достаточно памяти, доступной для выделения блока, исключение EOutOfMemory поднял.

Примечание: если память не нуждается в инициализации нуля, это больше вместо этого эффективно использовать GetMem.

// И нужно ли мне завершать работу с памятью после ее окончания? Если говорить о распределении памяти в целом, то выделенная память всегда должна быть освобождена.

Есть несколько исключений из этого -

  • Когда ваши объекты считаются ссылками
  • Когда другой объект заботится об объекте и освобождает его
...