2015-11-23 13 views
7

Đoạn mã sau cố gắng sử dụng tính năng đếm tham chiếu của Delphi.Rò rỉ bộ nhớ khi sử dụng tính năng đếm tham chiếu của Delphi

Tuy nhiên, FastMM4 trong báo cáo FullDebugMode DoStuff1 cho rò rỉ bộ nhớ trong khi DoStuff2 thì không. Bạn có thể giúp bình luận về lý do tại sao? Hai thủ tục này có nên hoạt động giống hệt nhau không?

program Project_SO; 

{$APPTYPE CONSOLE} 

uses 
    FastMM4, 
    SysUtils; 

type 
    ITestFunc = interface 
    ['{B3F6D9A7-FC77-40CE-9BBF-C42D7037A596}'] 
    function DoIt(X,Y: Integer): Integer; 
    end; 

    TTestFunc = class(TInterfacedObject, ITestFunc) 
    public 
    function DoIt(X,Y: Integer): Integer; 
    end; 
    TTestFuncClass = class of TTestFunc; 

{ TTestFunc } 

function TTestFunc.DoIt(X, Y: Integer): Integer; 
begin 
    Result := X + Y; 
end; 

function DoStuff1(Num1, Num2: Integer; OperationClass: TTestFuncClass): Integer; 
begin 
    Result := ITestFunc(OperationClass.Create).DoIt(Num1, Num2); 
end; 

function DoStuff2(Num1, Num2: Integer; OperationClass: TTestFuncClass): Integer; 
var I: ITestFunc; 
begin 
    I := ITestFunc(OperationClass.Create); 
    Result := I.DoIt(Num1, Num2); 
end; 

begin 
    Writeln(IntToStr(DoStuff1(3, 6, TTestFunc))); 
    Writeln(IntToStr(DoStuff2(3, 6, TTestFunc))); 
end. 
+2

Không sử dụng dàn diễn viên như vậy. Sử dụng 'I: = OperationClass.Create as ITestFunc;'. Bạn có thể thực sự chỉ làm 'I: = OperationClass.Create;', nhưng điều đó không đặt số tham chiếu là 1, điều này có thể gây ra vấn đề. –

+1

@Rudy Nó đặt số ref là 1 khi tôi được chỉ định. –

+1

@Xichen Lớp học của bạn sẽ cần một nhà xây dựng ảo –

Trả lời

5
Result := ITestFunc(OperationClass.Create).DoIt(Num1, Num2); 

Nowhere đây là một tham chiếu đến giao diện thực hiện. Một tham chiếu được thực hiện khi giao diện được gán cho một biến hoặc được truyền dưới dạng tham số giá trị. Trong thực tế, đi qua như là một tham số giá trị bằng, có thể được coi là tương đương ngữ nghĩa để gán cho một biến cục bộ trong khung của callee.

Nhưng không nơi nào trong mã này là tham chiếu được thực hiện. Và vì vậy, vì không có gì có liên quan đến giao diện nên không có cơ chế để nó bị phá hủy. Do đó bị rò rỉ.

var 
    I: ITestFunc; 
begin 
    I := ITestFunc(OperationClass.Create); 
    Result := I.DoIt(Num1, Num2); 
end; 

Trong phiên bản này, tham chiếu được thực hiện khi thực hiện bài tập. Khi biến cục bộ I rời khỏi phạm vi, số tham chiếu của nó giảm xuống 0 và đối tượng thực hiện bị hủy.

Lưu ý rằng diễn viên không được chọn là không cần thiết ở đây. Trình biên dịch biết rất rõ rằng TTestFunc thực hiện ITestFunc và mã của bạn tốt hơn nên được viết như thế này:

var 
    I: ITestFunc; 
begin 
    I := OperationClass.Create; 
    Result := I.DoIt(Num1, Num2); 
end; 

Như đã đề cập trong các ý kiến, bạn có thể loại bỏ các biến địa phương và sử dụng một kiểm tra as dàn diễn viên:

Result := (OperationClass.Create as ITestFunc).DoIt(Num1, Num2); 

Hậu quả của việc thực hiện diễn xuất as là một biến cục bộ ngầm định được khai báo, giao diện được gán. Điều đó có nghĩa là số lượng tham chiếu được tăng lên một, và sau đó được giảm xuống 0 khi phạm vi lá cục bộ tiềm ẩn.

Cuối cùng, lớp TTestFunc của bạn phải có một hàm tạo ảo vì bạn dự định khởi tạo nó với một lớp meta.

+0

Cảm ơn bạn rất nhiều vì sự giúp đỡ của bạn! Câu trả lời của bạn nói 'as-cast' sử dụng một biến cục bộ ngầm định, nhưng' hard-cast' thì không. Bạn có thể giúp xác nhận không? (Và mọi người nên tìm hiểu thông tin này ở đâu?) – SOUser

+1

Bạn có ý gì khi xác nhận. Các diễn viên không được kiểm soát không tạo ra một địa phương tiềm ẩn, các diễn viên kiểm tra không. Tôi không tin bất cứ điều gì trong số này được ghi lại ở bất cứ đâu. Xem xét câu trả lời này là điều tốt nhất tiếp theo. –

Các vấn đề liên quan