2013-01-24 20 views
7

Điều này liên quan đến một ứng dụng PHP 5.3 Cli xử lý rất nhiều dữ liệu một cách phức tạp, mất nhiều giờ để chạy. Ai đó phát hiện ra rằng việc tắt bộ sưu tập rác thải khiến nó chạy nhanh hơn rất nhiều (có thể tới 50%).Tại sao bộ thu gom rác của PHP làm chậm hiệu suất và cách quản lý bộ nhớ mà không có nó?

Bài viết duy nhất tôi đã đề cập đến đề cập đến lần truy cập hiệu suất này là http://derickrethans.nl/collecting-garbage-performance-considerations.html. Tôi không chắc chắn tôi làm theo nó hoàn toàn, nhưng nó có vẻ gợi ý rằng nó chỉ áp dụng cho mã với rất nhiều tài liệu tham khảo vòng tròn.

Ai đó có thể làm sáng tỏ điều này?

Ngoài ra, với điều kiện chúng tôi đã tắt gc, có cách nào để giảm bộ nhớ theo cách thủ công không? Sử dụng unset() đã được đề xuất. Một bài kiểm tra nhanh đã chỉ ra rằng tám mươi byte được giải phóng bởi unset() bất kể kích thước của đối tượng. Điều này cho thấy nó chỉ là mất tham chiếu, được sinh ra bởi những gì tôi đã đọc trực tuyến. Tôi có nghĩ rằng tám mươi byte này sẽ được giải phóng dù sao đi nữa, ngay cả khi không thu gom rác thải, khi biến đó nằm ngoài phạm vi?

Trả lời

4

Bạn vừa vô hiệu hóa tham chiếu vòng tròn-GC. Cái bình thường vẫn hoạt động.

Các bài kiểm tra GC chung, có hay không có zval s ("bộ nhớ"), không được tham chiếu bởi bất kỳ biến hoặc thuộc tính nào nữa và sẽ giải phóng bộ nhớ này. Một tham chiếu vòng tròn là, khi hai hoặc nhiều đối tượng tài liệu tham khảo nhau trực tiếp, hoặc gián tiếp

$a = new stdClass; 
$b = new stdClass; 
$a->b = $b; 
$b->a = $a; 
unset($a, $b); 

Bây giờ cả hai đối tượng tham khảo lẫn nhau, nhưng họ đều không tham chiếu từ bất cứ nơi nào khác, vì vậy họ không thể truy cập. Đây là, GC tham chiếu vòng cố gắng phát hiện, nhưng để tìm chúng, nó lặp lại trên mọi đối tượng đã biết và phát hiện ra, nếu có một tham chiếu "từ bên ngoài". Nó phức tạp hơn một chút, nhưng đơn giản hóa nó;) Vì vậy, trong các cấu trúc với nhiều tài liệu tham khảo, các vòng tròn đặc biệt, nó là một nhiệm vụ rất lớn.

Giá trị cần đề cập: Với unset() bạn chỉ xóa tham chiếu, nhưng không giải phóng bộ nhớ (trực tiếp). Điều này được thực hiện bởi GC sau đó (và nó làm cho một công việc tốt :))

+0

Tôi nghĩ rằng có thể là trường hợp, nhưng hướng dẫn là rất rõ ràng. Vì vậy, là một trong những thường xuyên không thể vô hiệu hóa? (Không phải là tôi muốn, chỉ quan tâm) – naomi

+0

@naomi Vâng, bạn không thể tắt nó. Cũng không có lý do gì (tác động rất nhỏ) và bởi vì bạn không thể giải phóng bộ nhớ từ bên trong PHP ('unset()' không làm điều này), bạn sẽ có một vấn đề lớn: D – KingCrunch

2

Bạn có thể xóa chu trình khỏi mã của mình theo cách thủ công bằng cách sử dụng unset. Bạn làm sạch chu kỳ từ các lớp bằng cách thực hiện một hàm __destruct. unset tất cả các biến riêng tư, được bảo vệ hoặc công khai tham chiếu đến các đối tượng khác.

Thật là tẻ nhạt nếu bạn áp dụng điều này cho một chương trình hiện có nhưng có thể thực hiện được.


class A { 
    public $ref; 
    public function __destruct() { 
     unset($this->ref); 
     echo "destruct"; 
    } 
} 
$a1 = new A(); 
$a2 = new A(); 
$a1->ref = $a2; 
$a2->ref = $a1; 

này không không công việc:

unset($a1, $a2); 
echo "--"; 
// prints --destructdestruct (in 5.3) 

này hoạt động:

$a1->__destruct(); 
unset($a1, $a2); 
echo "--"; 
// prints destructdestructdestruct-- (in 5.3) 
+0

Bạn nhận được ' + 1' cho lần sử dụng thứ hai của '__destruct()' Tôi tìm thấy _ever_: D hữu ích (Đầu tiên là "đóng tài nguyên, liên kết DB, tệp, ...") – KingCrunch

+0

OK, vì vậy, unset() không giải phóng bộ nhớ, nhưng nó KHÔNG loại bỏ tham chiếu vòng tròn, vì vậy nó là một ý tưởng tốt để sử dụng nó (nếu thích hợp) khi bộ thu tham chiếu vòng tròn bị tắt. Tôi có đúng không? – naomi

+0

Có, bạn có thể sử dụng 'unset' để loại bỏ các chu kỳ.' Unset' tự nó không giải phóng bộ nhớ, nó dọn dẹp các tham chiếu và nếu một đoạn dữ liệu không có tham chiếu thì nó sẽ được dọn sạch. Rất khó để phát hiện các chu kỳ – Halcyon

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