Delphi GETIPFROMHOST内存泄漏

Delphi GETIPFROMHOST内存泄漏,delphi,memory-leaks,delphi-7,winsock,winsock2,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: PaPI

我这里有一段代码,用于从主机名检索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;
程序项目1;
{$APPTYPE控制台}
使用
SysUtils,
温索克;
函数GetIPFromHost(const HostName:string):string;
类型
tapinadr=PInAddr的数组[0..10];
PaPInAddr=^TaPInAddr;
变量
phe:光能;
pptr:PaPInAddr;
i:整数;
开始
结果:='';
phe:=GetHostByName(PChar(主机名));
如果phe=零,则退出;
pPtr:=PaPInAddr(地址列表);
i:=0;
而pPtr^[i]nil do
开始
结果:=inet_ntoa(pptr^[i]^);
公司(一);
结束;
结束;
变量
wsaData:TWSAData;
开始
如果(WSAStartup($0202,wsaData)0),则开始
出口
结束;
真正的开始
睡眠(1000);
GetIPFromHost('localhost');
结束;
它工作正常,给了我IP地址。 不幸的是,我需要这个函数多次来比较DNS和IP地址

由于某种原因,我得到了一个大内存泄漏和我的程序内存增长非常快。 为什么会这样?我怎样才能释放记忆


提前感谢。

此代码不会泄漏。您的泄漏检测错误,或者您实际运行的代码比这更复杂,并且泄漏在您未显示的代码中

DelphiRTL在问题代码中分配的唯一内存是动态字符串。Delphi动态字符串处理不会泄漏。对WinSock、
gethostbyname
inet\u ntoa
的调用为WinSock分配内部内存

在下列情况下:

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

同样适用于:

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


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

以下是
JclSysInfo
中如何实现
GetIPAddress

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;
函数GetIPAddress(const HostName:string):string;
变量
R:整数;
WSAData:TWSAData;
主持人:光能;
主持人:字符串;
SockAddr:TSockAddrIn;
开始
结果:='';
R:=WSAStartup(MakeWord(1,1),WSAData);
如果R=0,则
尝试
主机:=主机名;
如果主机='',则
开始
SetLength(主机,最大路径);
GetHostName(PChar(主机),最大路径);
结束;
HostEnt:=GetHostByName(PChar(主机));
如果没有,那么
开始
SockAddr.sin_addr.S_addr:=Longint(PLongint(HostEnt^.h_addr_list^));
结果:=inet_ntoa(SockAddr.sin_addr);
结束;
最后
WSACleanup;
结束;
结束;
请注意,您丢失了


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


这段代码在DelphiXe2和XE3上运行

在uses子句中添加“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
//从主机获取IP地址的函数
函数GetIPFromHost(主机名:string):string;
类型
tapinadr=PInAddr的数组[0..10];
PaPInAddr=^TaPInAddr;
变量
phe:光能;
pptr:PaPInAddr;
i:整数;
GInitData:TWSAData;
开始
WSAStartup(101美元,GInitData);
尝试
结果:='';
phe:=GetHostByName(PAnsiChar(AnsiString((主机名));
如果phe=零,则退出;
pPtr:=PaPInAddr(地址列表);
i:=0;
而pPtr^[i]nil do
开始
结果:=字符串(inet_ntoa(pptr^[i]^));
公司(一);
结束;
最后
WSACleanup;
结束;
结束;E

这实际上是内存泄漏,还是进程加载到某些库中?这是内存泄漏。我正在使用Delphi7。循环只是表示每次调用函数时内存都会增加。我不知道delphi,但您不需要释放GetIPFromHost末尾phe指向的内存吗?我试过了,但之后整个程序都崩溃了FreeandNil@clime不,你没有。与德尔福无关。阅读winsock文档。问题中的代码调用WSAStartup。我不知道你在说什么,不需要。您可以在线程启动时调用WSAStartup,然后在线程关闭时再次调用它。在这种情况下,它是主线程,终结代码是毫无意义的,进程终止。每次您希望解析主机名时都进行初始化和最终确定是相当浪费的,因此Q中代码中使用的方法比您提供的代码更好。真的,这里没有泄漏。@DavidHeffernan,读一下关于WSACleanup的文件。如果您认为自己比官方MS文档中所述的更清楚,我建议您在这里发表评论,在启动WSAStartup后,不需要WSACleanup。每个人都知道,在进程终止时,操作系统将回收资源。如果你想的话,你可以调用它,但是不在问题的代码中也没什么坏处