2012-01-29 16 views
7

私は、ホスト名からIPアドレスをretriveするために右ここにこのコードを持っている:メモリリークGETIPFROMHOST

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アドレスを比較するには、この機能を数回必要とします。

何らかの理由で大きなメモリリークが発生し、プログラムのメモリが非常に高速に増加します。 どうして私はメモリを解放できますか?

ありがとうございます。

+0

に "のWinsock" を追加

のDelphi XE2およびXE3

に取り組んでいる、それは実際にはメモリリークです、またはいくつかのライブラリでは、プロセスの負荷のですか? –

+0

メモリリークです。私はDelphi7を使用しています。ループは、関数が呼び出されるたびにメモリが増加することを示しています。 –

+0

私はdelphiを知らないけど、GetIPFromHostの最後にpheが指すメモリを解放する必要はありませんか? – clime

答えて

3

このコードは、漏洩しません。漏れ検出に問題があるか、実際に実行しているコードがこれよりも複雑で、表示されていないコードに漏れがあります。

質問のコードでDelphi RTLによって割り当てられた唯一のメモリは、動的文字列です。 Delphiの動的文字列処理は漏れません。 WinSockへの呼び出し、gethostbynameおよびinet_ntoaは、WinSockに内部メモリを割り当てます。 gethostbyname関数によって返されるhostent構造体のためのメモリは、スレッドローカルストレージからのWinsock DLLによって内部的に割り当てられている

gethostbynameの場合

。スレッドに対してgethostbyaddrまたはgethostbyname関数が何回呼び出されても、単一のhostent構造体が割り当てられ、使用されます。同じスレッド上のgethostbyname関数またはgethostbyaddr関数に追加の呼び出しを行う場合は、返されたhostent構造体をアプリケーションバッファーにコピーする必要があります。それ以外の場合、戻り値は同じスレッド上の後続のgethostbynameまたはgethostbyaddr呼び出しによって上書きされます。スレッドが終了すると、返されたホスト構造体に割り当てられた内部メモリがWinsock DLLによって解放されます。 inet_ntoaため

、同様に:

INET_NTOAによって返された文字列は、Windowsソケットによって割り当てられたメモリに常駐します。アプリケーションでは、メモリの割り当て方法について何も仮定しないでください。返される文字列は、同じスレッド内で次のWindows Sockets関数呼び出しが行われるまで有効であることが保証されています。

プロセス終了時にリソースを再利用することはなく、無意味であるため、問題のコードは大丈夫ですWSACleanupを呼び出さないことは事実であるが。ここで

4

GetIPAddressJclSysInfoに実装されている方法です:あなたはWSACleanupが欠落している

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; 

注意。


アプリケーションまたはDLLは、それがWindowsソケットサービスを使用する前に成功したWSAStartupを呼び出しを行う必要があります。 Windowsソケットの使用が完了したら、アプリケーションまたはDLLはWSACleanupを呼び出してWindows Sockets実装から自身を登録解除し、アプリケーションまたはDLLに代わって割り当てられたすべてのリソースを解放できるようにする必要があります。

+0

質問のコードはWSAStartupを呼び出します。あなたは何をしているのか分かりません。 –

+3

WSACleanupが表示されますか? – kobik

+0

これは必要ありません。スレッドの開始時にWSAStartupを呼び出し、スレッドが終了したときにWSAStartupを再度呼び出すことができます。この場合、それはメインスレッドであり、終了コードはむしろ無意味であり、プロセスの終了です。ホスト名を解決するたびに、初期化してファイナライズするのはむしろ無駄です。そのため、Qのコードで使用されている方法は、あなたが提示したコードよりも優れています。本当にここには漏れはありません。 –

2

このコードは、uses節

//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