2012-01-29 26 views
7

tengo este código aquí retrive la dirección IP de un nombre de host:pérdida de memoria 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; 

que trabaja muy bien y me da la dirección IP. Lamentablemente, necesito esta función un par de veces para comparar un DNS con una dirección IP.

Por alguna razón, recibo una gran pérdida de memoria y la memoria de mi programa aumenta muy rápido. ¿Por qué es eso y cómo puedo liberar la memoria?

Gracias de antemano.

+0

¿Es realmente una pérdida de memoria, o es su carga de proceso en algunas bibliotecas? –

+0

es una pérdida de memoria. Estoy usando Delphi7. el bucle solo representa que cada vez que se llama a la función, la memoria aumenta. –

+0

No sé delphi pero ¿no necesitas liberar memoria apuntada por phe al final de GetIPFromHost? – clime

Respuesta

3

Este código no tiene fugas. O bien su detección de fugas es defectuosa o el código que está ejecutando realmente es más complejo que esto y la fuga está en el código que no ha mostrado.

La única memoria asignada por Delphi RTL, en el código de la pregunta, es para las cadenas dinámicas. El manejo de cadena dinámico de Delphi no tiene fugas. Las llamadas a WinSock, gethostbyname y inet_ntoa asignan memoria interna a WinSock.

En el caso de gethostbyname:

La memoria para la estructura hostent devuelto por la función gethostbyname se asigna internamente por el Winsock DLL a partir de hilos de almacenamiento local. Solo se asigna y utiliza una sola estructura de hospedaje, sin importar cuántas veces se invoquen las funciones gethostbyaddr o gethostbyname en la cadena. La estructura de hosent devuelta debe copiarse en un búfer de aplicación si se deben realizar llamadas adicionales a las funciones gethostbyname o gethostbyaddr en el mismo hilo. De lo contrario, el valor de retorno se sobrescribirá con las llamadas gethostbyname o gethostbyaddr subsiguientes en el mismo subproceso. La memoria interna asignada para la estructura de Hostent devuelta es liberada por Winsock DLL cuando el hilo se cierra.

y lo mismo para inet_ntoa:

La cadena devuelta por inet_ntoa reside en la memoria asignada por Windows Sockets. La aplicación no debe hacer suposiciones sobre la forma en que se asigna la memoria. Se garantiza que la cadena devuelta será válida solo hasta que se realice la siguiente llamada a la función de Windows Sockets dentro del mismo hilo.

Si bien es cierto que el código en la pregunta no llama WSACleanup que está bien, ya que es bastante inútil para reclamar recursos en tiempo de la terminación del proceso.

4

Aquí es cómo se implementa en GetIPAddressJclSysInfo:

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; 

Tenga en cuenta que se echa en falta WSACleanup.


Una aplicación o DLL se requiere para llevar a cabo una exitosa llamada WSAStartup antes de que pueda utilizar los servicios de Windows Sockets. Cuando haya completado el uso de Windows Sockets, la aplicación o DLL debe llamar a WSACleanup para eliminar el registro de una implementación de Windows Sockets y permitir que la implementación libere los recursos asignados en nombre de la aplicación o DLL.

+0

El código en la pregunta llama WSAStartup. No sé qué punto estás haciendo. –

+3

¿ves un WSACleanup? – kobik

+0

No es necesario. Puede llamar a WSAStartup cuando se inicia el hilo y luego volver a llamar cuando se cierra el hilo. En este caso, es el hilo principal y el código de finalización es bastante inútil y la terminación del proceso. Es un desperdicio inicializar y finalizar cada vez que desea resolver un nombre de host, por lo que el enfoque utilizado en el código de la Q es mejor que el código que presenta. Realmente, no hay filtración aquí. –

2

Este código está trabajando en Delphi XE2 y XE3

Añadir "Winsock" para usos cláusula

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