2011-10-05 57 views
6

Tôi có một tập lệnh php sử dụng Doctrine2 và Zend để tính toán một số thứ từ cơ sở dữ liệu và gửi một số email cho 30.000 người dùng.Có cách nào để biết đối tượng nào và tôi có bao nhiêu bộ nhớ trong bộ nhớ?

Tập lệnh của tôi bị rò rỉ bộ nhớ và tôi muốn biết các đối tượng nào đang tiêu thụ bộ nhớ đó, và nếu có thể là người giữ tham chiếu đến chúng (do đó không cho phép chúng được phát hành).

Im sử dụng php 5.3.x, vì vậy các tham chiếu thông thường không phải là vấn đề.

Tôi đã thử sử dụng khả năng theo dõi xdebug để nhận mem_delta mà không thành công (quá nhiều dữ liệu).

Ive đã thử thêm bộ nhớ memory_get_usage theo cách thủ công trước và sau các chức năng quan trọng. Nhưng kết luận duy nhất mà tôi nhận được là tôi mất khoảng 400k cho mỗi người dùng và 3000 lần người dùng mang lại cho tôi 1Gb mà tôi có sẵn.

Có cách nào khác để biết vị trí và lý do bộ nhớ bị rò rỉ không? Cảm ơn

+1

Vâng, người dùng nên được xử lý cái khác, nên chỉ có 400k bộ nhớ cần thiết! Nếu mỗi chu kỳ làm tăng mức sử dụng bộ nhớ, một cái gì đó trong thiết kế của bạn là sai lầm nghiêm trọng! – markus

+0

Vâng, tôi có một vòng lặp gọi một hàm thực hiện các thao tác sau: Nhận thông tin cho người dùng, tính toán (với lưu trữ được bao gồm), gửi thư, phát hành tài nguyên. Và mỗi người dùng độc lập với nhau, vì vậy một cách rõ ràng các tài nguyên không được phát hành –

+0

Bạn đã xem xét trình quản lý thực thể của học thuyết chưa? Tôi không quen với học thuyết nhưng nó có thể lưu trữ các tham chiếu đến các thực thể/proxy/... cho tất cả 30k người dùng. – Fge

Trả lời

2

Bạn có thể thử gửi nói 10 email và sau đó chèn này

get_defined_vars(); 

http://nz.php.net/manual/en/function.get-defined-vars.php

Vào cuối của kịch bản hoặc sau khi email được gửi (tùy thuộc vào cách mã của bạn được thiết lập) .

Điều này sẽ cho bạn biết nội dung nào vẫn được tải và những gì bạn có thể bỏ đặt/biến thành tham chiếu.

Ngoài ra nếu có quá nhiều thứ được tải, bạn sẽ nhận được điều này gần bắt đầu và kết thúc mã của bạn và tìm ra sự khác biệt.

+0

Cảm ơn, điều đó có vẻ hữu ích. Tôi sẽ thử điều đó trong vòng lặp của tôi. Từ tài liệu, điều duy nhất khiến tôi lo lắng là nó chỉ cho tôi thông tin về đối tượng trong phạm vi. Và tôi đoán vấn đề bộ nhớ thoát vì nó nằm ngoài phạm vi. –

0

Đây không phải là công cụ sẽ cung cấp cho bạn những gì bạn cần nhưng có thể nó sẽ giúp bạn. Nếu bạn chưa sẵn sàng, bạn có thể triển khai mẫu bản đồ nhận dạng nơi mỗi khi bạn tạo một đối tượng được đăng ký với bản đồ nhận dạng, bất cứ lúc nào bạn có thể gọi IM và xem đối tượng nào được tải hoặc yêu cầu tải nạp các đối tượng.

http://martinfowler.com/eaaCatalog/identityMap.html

+0

@Joey_Rivera Mô hình đó đã được thực hiện bởi học thuyết, và tôi sẽ sử dụng nó nếu cần hiệu suất trong thời gian truy vấn, vấn đề của tôi là cách khác xung quanh. Tôi không cần phải thêm nhiều tham chiếu đến các đối tượng, tôi cần một cách để giảm số lượng tham chiếu. –

2

30.000 đối tượng để hydrat là khá nhiều. Doctrine 2 là ổn định, nhưng có một số lỗi, vì vậy tôi không quá ngạc nhiên về vấn đề rò rỉ bộ nhớ của bạn.

Mặc dù với các tập dữ liệu nhỏ hơn, tôi đã có một số thành công tốt khi sử dụng các học thuyết batch processing khả năng và tạo kết quả có thể lặp lại.

Bạn có thể sử dụng mã từ các ví dụ và thêm gc_collect_cycles() sau mỗi lần lặp lại. Bạn phải kiểm tra nó, nhưng đối với tôi kích thước hàng loạt khoảng 100 hoặc như vậy làm việc khá tốt - con số đó đã cho một sự cân bằng tốt giữa hiệu suất và sử dụng bộ nhớ. Nó khá quan trọng là kịch bản nhận ra những thực thể được xử lý để nó có thể được khởi động lại mà không có bất kỳ vấn đề gì và tiếp tục hoạt động bình thường mà không cần gửi email hai lần.

$batchSize = 20; 
$i = 0; 
$q = $em->createQuery('select u from MyProject\Model\User u'); 
$iterableResult = $q->iterate(); 
while (($row = $iterableResult->next()) !== false) { 
    $entity = $row[0]; 

    // do stuff with $entity here 
    // mark entity as processed 

    if (($i % $batchSize) == 0) { 
     $em->flush(); 
     $em->clear(); 

     gc_collect_cycles(); 
    } 
    ++$i; 
} 

Dù sao, có thể bạn nên suy nghĩ lại kiến ​​trúc của mình cho tập lệnh đó một chút, vì ORM không phù hợp để xử lý khối dữ liệu lớn. Có lẽ bạn có thể lấy đi bằng cách làm việc trên các hàng SQL thô?

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