Утечка памяти ГЕТИПФРОМХОСТ - PullRequest
7 голосов
/ 29 января 2012

У меня есть этот код прямо здесь, чтобы получить IP-адрес от имени хоста:

program Project1;

{$APPTYPE CONSOLE}

uses
  SysUtils,
  winsock;

function GetIPFromHost(const HostName: string): string;
type
  TaPInAddr = array[0..10] of PInAddr;
  PaPInAddr = ^TaPInAddr;
var
  phe: PHostEnt;
  pptr: PaPInAddr;
  i: Integer;
begin
  Result := '';
  phe := GetHostByName(PChar(HostName));
  if phe = nil then Exit;
  pPtr := PaPInAddr(phe^.h_addr_list);
  i := 0;
  while pPtr^[i] <> nil do
  begin
    Result := inet_ntoa(pptr^[i]^);
    Inc(i);
  end;
end;

var
wsaData: TWSAData;

begin

if (WSAStartup($0202, wsaData) <> 0) then begin
      Exit;
end;

while true do begin
sleep (1000);
GetIPFromHost ('localhost');
end;

, он работает нормально и дает мне IP-адрес.К сожалению, мне нужна эта функция пару раз для сравнения DNS с IP-адресом.

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

Заранее спасибо.

Ответы [ 3 ]

4 голосов
/ 29 января 2012

Вот как GetIPAddress реализовано в JclSysInfo:

function GetIPAddress(const HostName: string): string;
var
  R: Integer;
  WSAData: TWSAData;
  HostEnt: PHostEnt;
  Host: string;
  SockAddr: TSockAddrIn;
begin
  Result := '';
  R := WSAStartup(MakeWord(1, 1), WSAData);
  if R = 0 then
  try
    Host := HostName;
    if Host = '' then
    begin
      SetLength(Host, MAX_PATH);
      GetHostName(PChar(Host), MAX_PATH);
    end;
    HostEnt := GetHostByName(PChar(Host));
    if HostEnt <> nil then
    begin
      SockAddr.sin_addr.S_addr := Longint(PLongint(HostEnt^.h_addr_list^)^);
      Result := inet_ntoa(SockAddr.sin_addr);
    end;
  finally
    WSACleanup;
  end;
end;

Обратите внимание, что вам не хватает WSACleanup.


Приложение или DLL должны выполнить успешный вызов WSAStartup, прежде чем они смогут использовать службы Windows Sockets.Когда приложение Windows Sockets завершено, приложение или DLL должны вызвать WSACleanup, чтобы отменить регистрацию в реализации Windows Sockets и разрешить реализации освободить все ресурсы, выделенные от имени приложения или DLL.

3 голосов
/ 29 января 2012

Этот код не течет.Либо ваше обнаружение утечки неисправно, либо код, который вы на самом деле выполняете, является более сложным, чем этот, и утечка находится в коде, который вы не показали.

Единственная память, выделенная Delphi RTL, в кодев вопросе, для динамических строк.Динамическая обработка строк в Delphi не протекает.При вызовах WinSock, gethostbyname и inet_ntoa выделяется внутренняя память для WinSock.

В случае gethostbyname:

Память дляструктура hostent, возвращаемая функцией gethostbyname, распределяется внутри Winsock DLL из локального хранилища потока.Выделяется и используется только одна структура hostent, независимо от того, сколько раз функции gethostbyaddr или gethostbyname вызываются в потоке.Возвращаемая структура hostent должна быть скопирована в буфер приложения, если необходимо выполнить дополнительные вызовы для функций gethostbyname или gethostbyaddr в том же потоке.В противном случае возвращаемое значение будет перезаписано последующими вызовами gethostbyname или gethostbyaddr в том же потоке.Внутренняя память, выделенная для возвращенной структуры hostent, освобождается Winsock DLL при выходе из потока.

И также для inet_ntoa:

Строка, возвращаемая inet_ntoa, находится в памяти, выделенной сокетами Windows.Приложение не должно делать никаких предположений о том, каким образом выделяется память.Возвращаемая строка гарантированно будет действительной только до следующего вызова функции Windows Sockets в том же потоке.

Хотя верно то, что код в вопросе не вызывает WSACleanup это нормально, так как возвращать ресурсы во время завершения процесса довольно бессмысленно.

2 голосов
/ 05 июня 2013

Этот код работает на Delphi XE2 и XE3

Добавить " Winsock " к пункту использования

//function to get the IP Address from a Host
function GetIPFromHost(HostName: string): string;
type
  TaPInAddr = array[0..10] of PInAddr;
  PaPInAddr = ^TaPInAddr;
var
  phe: PHostEnt;
  pptr: PaPInAddr;
  i: Integer;
  GInitData: TWSAData;
begin
  WSAStartup($101, GInitData);
  try
    Result := '';
    phe := GetHostByName(PAnsiChar(AnsiString((HostName))));
    if phe = nil then Exit;
    pPtr := PaPInAddr(phe^.h_addr_list);
    i := 0;
    while pPtr^[i] <> nil do
    begin
      Result := string(inet_ntoa(pptr^[i]^));
      Inc(i);
    end;
  finally
    WSACleanup;
  end;
end;e
...