Việc sử dụng phương pháp hoặc thuộc tính của tham chiếu null luôn là sai, ngay cả khi nó dường như đôi khi hoạt động.
FreeAndNil
thực sự không thể được sử dụng để phát hiện các giải thoát kép. An toàn để gọi số FreeAndNil
trên biến đã có. Vì nó an toàn, nó không giúp bạn phát hiện bất cứ điều gì.
Đây không phải là lỗi con trỏ cũ. Đây là một lỗi tham chiếu null. Lỗi con trỏ cũ là khi bạn giải phóng một đối tượng nhưng không phải đã xóa tất cả các biến tham chiếu đến nó. Sau đó biến vẫn giữ địa chỉ cũ của đối tượng. Đó là những thứ rất khó phát hiện. Bạn có thể nhận được một lỗi như thế này:
MStr := TMemoryStream.Create;
MStr.Free;
MStr.Size := 0;
Bạn cũng có thể có được một như thế này:
MStr := TMemoryStream.Create;
OtherStr := MStr;
FreeAndNil(MStr);
OtherStr.Size := 0;
Sử dụng MStr.Size
sau khi bạn đã giải phóng đối tượng MStr
tham chiếu là một lỗi, và nó sẽ nâng cao một ngoại lệ. Cho dù có tăng ngoại lệ hay không phụ thuộc vào việc triển khai. Có lẽ nó sẽ, và có lẽ nó sẽ không. Nó không phải ngẫu nhiên, mặc dù.
Nếu bạn đang tìm kiếm lỗi kép miễn phí, bạn có thể sử dụng trình gỡ lỗi mà FastMM cung cấp, như những người khác đã đề xuất. Nó hoạt động bằng cách không thực sự giải phóng bộ nhớ trở lại hệ điều hành, hoặc thậm chí trở lại hồ bơi bộ nhớ trong của Delphi. Thay vào đó, nó ghi dữ liệu đã biết xấu vào không gian bộ nhớ của đối tượng, vì vậy khi bạn nhìn thấy các giá trị đó, bạn sẽ biết bạn đang đọc từ một cái gì đó mà bạn đã giải phóng. Nó cũng sửa đổi VMT của đối tượng để lần sau bạn gọi một phương thức ảo trên tham chiếu đối tượng đó, bạn sẽ nhận được một ngoại lệ có thể dự đoán được, và nó thậm chí sẽ cho bạn biết đối tượng được giải phóng nào mà bạn đã cố gắng sử dụng. Khi bạn cố gắng giải phóng đối tượng một lần nữa, nó có thể cho bạn biết không chỉ rằng bạn đã giải phóng nó, mà còn là nơi nó được giải phóng lần đầu tiên (với một dấu vết ngăn xếp), và nơi nó được cấp phát.Nó cũng thu thập thông tin đó để báo cáo về rò rỉ bộ nhớ, trong đó bạn giải phóng một đối tượng ít hơn thay vì một lần thay vì nhiều hơn.
Ngoài ra còn có những thói quen bạn có thể sử dụng để tránh vấn đề này đối với mã tương lai:
- Giảm việc sử dụng các biến toàn cục. Biến toàn cầu có thể được sửa đổi bởi bất kỳ mã nào trong suốt chương trình, buộc bạn phải băn khoăn bất cứ khi nào bạn sử dụng nó, "Giá trị của biến này vẫn hợp lệ hay đã có một số mã khác miễn phí?" Khi bạn giới hạn phạm vi của một biến, bạn giảm số lượng mã bạn phải xem xét trong chương trình của mình khi tìm kiếm lý do biến không có giá trị bạn mong đợi.
- Hãy rõ ràng về người sở hữu một đối tượng. Khi có hai đoạn mã có quyền truy cập vào cùng một đối tượng, bạn cần biết mã nào trong số các mã đó là sở hữu đối tượng. Họ có thể có một biến khác nhau để tham chiếu đối tượng, nhưng vẫn chỉ có một đối tượng ở đó. Nếu một đoạn mã gọi
FreeAndNil
trên biến của nó, biến đó vẫn không thay đổi. Nếu mã khác nghĩ rằng nó sở hữu đối tượng, thì bạn đang gặp rắc rối. (Khái niệm về chủ sở hữu này không nhất thiết phải gắn với thuộc tính TComponent.Owner
. Không cần phải là đối tượng sở hữu nó; nó có thể là một hệ thống con chung của chương trình của bạn.)
- Không liên tục tham chiếu đến các đối tượng bạn không sở hữu. Nếu bạn không giữ các tham chiếu lâu dài cho một đối tượng, thì bạn không phải lo lắng về việc liệu các tham chiếu đó có còn hiệu lực hay không. Tham chiếu liên tục duy nhất phải ở trong mã sở hữu đối tượng. Bất kỳ mã nào khác cần sử dụng đối tượng đó sẽ nhận được tham chiếu dưới dạng thông số đầu vào, sử dụng đối tượng và sau đó loại bỏ tham chiếu khi nó trả về kết quả của nó.
Nguồn
2008-12-12 21:42:12
Tôi nghĩ rằng 'ai đó' là mất tích một số khái niệm quan trọng. –
Như tôi đã nói trước đó, FastMM có một tùy chọn thực hiện những gì bạn mô tả. Rob chỉ ra rằng nó sẽ ghi đè lên bộ nhớ với 'số ma thuật' để nó có thể phát hiện loại lỗi này. Hãy nhìn vào nó. Tải xuống toàn bộ FastMM4 và bật ghi nhật ký vào tệp. Tôi đã tìm thấy nó khá hữu ích. – Vegar
FreeAndNil() không nil ra bộ nhớ bị chiếm đóng bởi các trường hợp, nó nils tham chiếu thông qua. – Bevan