2012-01-29 27 views
7

tôi có mã này ngay tại đây để truy xuất các địa chỉ IP từ một hostname:Memory Leak 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; 

nó hoạt động tốt và mang lại cho tôi địa chỉ IP. Thật không may, tôi cần chức năng này một vài lần để so sánh DNS với địa chỉ IP.

Vì lý do nào đó, tôi nhận được Rò rỉ bộ nhớ lớn và bộ nhớ của chương trình của tôi tăng rất nhanh. Tại sao điều đó và làm thế nào tôi có thể giải phóng bộ nhớ?

Xin cảm ơn trước.

+0

Có thực sự là một rò rỉ bộ nhớ, hoặc là quá trình tải của bạn trong một số thư viện? –

+0

nó là một rò rỉ bộ nhớ. Tôi đang sử dụng Delphi7. vòng lặp chỉ biểu thị rằng mỗi khi hàm được gọi là bộ nhớ tăng lên. –

+0

Tôi không biết delphi nhưng bạn không cần phải giải phóng bộ nhớ được chỉ bởi phe ở cuối GetIPFromHost? – clime

Trả lời

3

Mã này không bị rò rỉ. Hoặc phát hiện rò rỉ của bạn bị lỗi, hoặc mã bạn đang thực sự chạy là phức tạp hơn này và rò rỉ là trong mã mà bạn đã không được hiển thị.

Bộ nhớ duy nhất được phân bổ bởi RTL Delphi, trong mã trong câu hỏi, là dành cho các chuỗi động. Xử lý chuỗi động Delphi không bị rò rỉ. Các cuộc gọi tới WinSock, gethostbynameinet_ntoa cấp phát bộ nhớ nội bộ cho WinSock.

Trong trường hợp của gethostbyname:

Các bộ nhớ cho cấu trúc hostent trả về bởi hàm GetHostByName được phân bổ trong nội bộ của Winsock DLL từ chủ đề lưu trữ địa phương. Chỉ có một cấu trúc máy chủ duy nhất được cấp phát và sử dụng, bất kể hàm gethostbyaddr hoặc gethostbyname được gọi bao nhiêu lần trong chuỗi. Cấu trúc hostent được trả về phải được sao chép vào bộ đệm ứng dụng nếu các cuộc gọi bổ sung được thực hiện cho các hàm gethostbyname hoặc gethostbyaddr trên cùng một luồng. Nếu không, giá trị trả lại sẽ bị ghi đè bởi các lệnh gethostbyname hoặc gethostbyaddr tiếp theo trên cùng một luồng. Bộ nhớ trong được cấp phát cho cấu trúc hostent được trả về được phát hành bởi Winsock DLL khi thoát khỏi thread.

Và tương tự như vậy cho inet_ntoa:

Chuỗi trả về bởi inet_ntoa nằm trong bộ nhớ được cấp phát bởi Windows Sockets. Ứng dụng không nên đưa ra bất kỳ giả định nào về cách thức bộ nhớ được cấp phát. Chuỗi được trả về được đảm bảo chỉ hợp lệ cho đến khi cuộc gọi hàm Windows Sockets tiếp theo được thực hiện trong cùng một chuỗi.

Trong khi đúng là mã trong câu hỏi không gọi là số WSACleanup thì tốt vì không thể lấy lại tài nguyên tại thời điểm chấm dứt quá trình.

4

Sau đây là cách GetIPAddress được thực hiện trong 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; 

Lưu ý rằng bạn đang thiếu WSACleanup.


Đơn hoặc DLL là cần thiết để thực hiện một cuộc gọi WSAStartup thành công trước khi nó có thể sử dụng các dịch vụ Windows Sockets. Khi nó đã hoàn thành việc sử dụng Windows Sockets, ứng dụng hoặc DLL phải gọi WSACleanup để tự hủy đăng ký từ việc thực thi Windows Sockets và cho phép thực thi giải phóng bất kỳ tài nguyên nào được phân bổ thay cho ứng dụng hoặc DLL.

+0

Mã trong câu hỏi gọi là WSAStartup. Tôi không biết bạn đang làm gì. –

+3

bạn có thấy WSACleanup không? – kobik

+0

Không cần thiết. Bạn có thể gọi WSAStartup khi chuỗi của bạn bắt đầu và sau đó gọi lại khi chuỗi của bạn đóng. Trong trường hợp này, đó là chủ đề chính và mã quyết toán là vô nghĩa và quá trình chấm dứt. Sẽ khá lãng phí khi khởi tạo và hoàn thiện mỗi lần bạn muốn giải quyết tên máy chủ để cách tiếp cận được sử dụng trong mã trong Q tốt hơn mã bạn trình bày. Thực sự, không có rò rỉ ở đây. –

2

Mã này đang làm việc trên Delphi XE2 và XE3

Add "Winsock" mục đích sử dụng khoản

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