内存泄漏GETIPFROMHOST

时间:2012-01-29 03:33:20

标签: delphi memory-leaks delphi-7 winsock winsock2

我这里有这个代码来从主机名中检索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 个答案:

答案 0 :(得分:4)

以下是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


  

在使用Windows套接字服务之前,需要应用程序或DLL才能执行成功的WSAStartup调用。完成Windows套接字的使用后,应用程序或DLL必须调用WSACleanup从Windows套接字实现中注销自身,并允许实现释放代表应用程序或DLL分配的任何资源。

答案 1 :(得分:3)

此代码不会泄漏。您的泄漏检测有问题,或者您实际运行的代码比此更复杂,泄漏位于您未显示的代码中。

Delphi RTL在问题代码中分配的唯一内存是动态字符串。 Delphi动态字符串处理不会泄漏。对WinSock,gethostbynameinet_ntoa的调用会为WinSock内部分配内存。

如果是gethostbyname

  

gethostbyname函数返回的hostent结构的内存由Winsock DLL从线程本地存储内部分配。无论在线程上调用gethostbyaddr或gethostbyname函数多少次,都只分配和使用一个hostent结构。如果要对同一线程上的gethostbyname或gethostbyaddr函数进行其他调用,则必须将返回的hostent结构复制到应用程序缓冲区。否则,返回值将被同一线程上的后续gethostbyname或gethostbyaddr调用覆盖。当线程退出时,Winsock DLL将释放为返回的hostent结构分配的内部内存。

同样适用于inet_ntoa

  

inet_ntoa返回的字符串驻留在由Windows套接字分配的内存中。应用程序不应该对内存的分配方式做任何假设。返回的字符串保证仅在同一个线程中进行下一个Windows套接字函数调用之前有效。

虽然问题中的代码确实没有调用WSACleanup这是正确的,因为在进程终止时回收资源是没有意义的。

答案 2 :(得分:2)

此代码正在处理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