2011-08-18 46 views
6

Trong khi gỡ lỗi một đoạn mã đã cạn kiệt bộ nhớ, tôi đã tìm thấy một vấn đề rất thú vị và quan trọng nhất là tôi không biết cách khắc phục nó.hủy một đối tượng có tham chiếu đến chính nó

Ứng dụng bao gồm khoảng một đối tượng Survey đơn, chứa một số đối tượng Question. Các đối tượng Câu hỏi có chứa một tham chiếu đến Bản khảo sát mà chúng đang có, điều này là cần thiết để có thể lấy các câu trả lời từ các Câu hỏi khác chẳng hạn.


Vòng lặp sau đây đã gây ra lỗi tràn bộ nhớ:

foreach ($survey_ids_arr as $survey_id) { 
    $Survey = new Survey($survey_id); 
} 

Không có gì thực sự kỳ lạ đang xảy ra trong các nhà xây dựng Khảo sát;

  • lấy thuộc tính của nó từ cơ sở dữ liệu
  • lấy thuộc tính tất cả các câu hỏi từ cơ sở dữ liệu
  • tạo ra một đối tượng Câu hỏi cho mỗi câu hỏi (đi qua một tham chiếu đến $ này)
  • thêm tất cả đối tượng Câu hỏi cho một mảng nội bộ

và nhìn vào mã, bạn sẽ nói rằng trong mỗi lần lặp, đối tượng sẽ bị xóa khỏi bộ nhớ vì biến $ Survey bị ghi đè. Đúng?? Sai :)

Bộ nhớ được xếp chồng khi tập lệnh đi qua vòng lặp - thêm các cuộc gọi memory_get_usage() cho biết bộ nhớ được đối tượng khảo sát sử dụng không được giải phóng như mong đợi, tại thời điểm này đối tượng khác được gán cho biến số $Survey . Ngay cả gọi unset($Survey) ở cuối vòng lặp không giải phóng bộ nhớ.


Thủ phạm là tham chiếu đến $this được chuyển đến đối tượng Câu hỏi khi tạo. Những tài liệu tham khảo ngăn chặn các đối tượng được xóa khỏi bộ nhớ - như hướng dẫn trên tiểu bang php.net:

Phương pháp destructor sẽ được gọi ngay khi tất cả các tham chiếu đến một đối tượng cụ thể được loại bỏ

Vì vậy, những gì ngăn cản các đối tượng được làm sạch, là các tài liệu tham khảo nó có trong nó cho chính nó. Đẹp đấy chứ hả? :)

Vì vậy, vấn đề là đối tượng của tôi là kẻ giết người bộ nhớ. Thật không may, tôi không thể nghĩ ra một giải pháp (khác hơn là viết một phương pháp xấu xí mà xóa các câu hỏi và gọi đó từ vòng lặp). Các destructor trong khảo sát không phải là một lựa chọn; như đã nêu ở trên, điều này không được gọi là đối tượng Câu hỏi vẫn có tham chiếu.

Bất kỳ ý tưởng nào? Ai đó đã phải chạy vào vấn đề này rồi - các đối tượng cha-chứa-con không phải là một kiến ​​trúc không phổ biến, phải không?

+0

Vấn đề là một nghịch lý trong thiết kế của bạn: bạn muốn ngăn chặn đối tượng được xóa khỏi bộ nhớ nhưng bạn muốn xóa nó? – m0skit0

+1

Vấn đề này được giải quyết trong php 5.3. Bạn sử dụng phiên bản PHP nào? – J0HN

+0

Bạn đúng J0HN, tôi chỉ tìm thấy báo cáo lỗi! https://bugs.php.net/bug.php?id=33595 – Rijk

Trả lời

2

Vì vậy, đây là câu trả lời: chuyển sang PHP 5.3, vì vấn đề này là resolved trong đó. Nếu bạn phải làm việc với PHP < 5.3.0, bạn có trách nhiệm giải phóng các đối tượng được chụp trong tham chiếu vòng kết nối.Aproach có thể là giới thiệu phương pháp đặc biệt sẽ loại bỏ các liên kết đến các đối tượng con để cho phép chúng được thu thập bởi GC

P.S. cũng có thể hữu ích cho ai đó, Doctrine 1.2 có liên kết như vậy trong các mô hình, do đó, nó có thể bị rò rỉ bộ nhớ, đặc biệt nếu bạn tìm nạp nhiều thực thể từ cơ sở dữ liệu của mình. Nếu bạn đang đối mặt với vấn đề này, hãy thử (1) giảm số lượng thực thể được tìm nạp (ví dụ: hydrate dưới dạng mảng), (2) xử lý các thực thể có yêu cầu sql thô.

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