2010-03-17 20 views
17

Tôi đang sử dụng Symfony 1.4 và Doctrine.Làm thế nào để sử dụng ít bộ nhớ hơn khi chạy một tác vụ trong Symfony 1.4?

Cho đến nay tôi không gặp vấn đề khi chạy tác vụ với Symfony. Nhưng bây giờ mà tôi phải nhập khẩu một lượng khá lớn các dữ liệu và lưu chúng trong cơ sở dữ liệu, tôi nhận được khét tiếng

"Fatal Error: Allowed memory size of XXXX bytes exhausted"

Trong quá trình nhập này, tôi chỉ tạo ra các đối tượng mới, thiết lập một vài lĩnh vực và lưu chúng .

Tôi khá chắc chắn rằng nó có liên quan đến số lượng đối tượng tôi đang tạo khi lưu dữ liệu. Việc bỏ đặt các đối tượng đó không làm bất cứ điều gì.

Có cách nào tốt nhất để hạn chế sử dụng bộ nhớ trong Symfony không?

+1

+1 câu hỏi hay; đó là thứ không được đề cập trong tài liệu của Symfony! – richsage

+0

Một câu trả lời khác để tránh rò rỉ bộ nhớ http://stackoverflow.com/a/4066680/569101 – j0k

Trả lời

11

Tôi đã xem qua điều này và có một số kỹ thuật tôi thấy thực sự đã giúp ích rất nhiều trong việc sử dụng bộ nhớ của Doctrine.

1: Nếu có thể, hãy hydrat kết quả truy vấn Doctrine xuống một mảng. Bạn có thể thực hiện việc này như sau:

$query = self::createQuery("q")-> 
    ... 
    ->setHydrationMode(Doctrine::HYDRATE_ARRAY) 
    ->execute(); 

Lực lượng này KHÔNG tạo ra các vật lớn, mà thay vào đó làm giảm một mảng. Rõ ràng là hãy nhớ rằng nếu bạn làm điều này, bạn sẽ mất khả năng gọi các phương thức v.v., vì vậy điều này chỉ tốt nếu bạn đang sử dụng nó để đọc các giá trị trường, v.v.

2: Giải phóng kết quả của bạn sau khi thực thi. Điều này được ghi lại trong một khu vực nhỏ của tài liệu Doctrine, nhưng nó thực sự đã giúp tôi thực hiện nhiệm vụ nhập khẩu:

$query->free(); 

Vậy đó. Bạn cũng có thể làm điều này trên các đối tượng mà bạn đã tạo, ví dụ: $myObj->free(); và điều này buộc Doctrine phải loại bỏ tất cả các tham chiếu vòng tròn mà nó tạo ra. Lưu ý rằng các tham chiếu vòng tròn được tự động giải phóng khỏi PHP 5.3 trở đi khi xóa một đối tượng thông qua phạm vi PHP hoặc unset(), nhưng trước đó bạn sẽ cần phải tự mình thực hiện.

Biến chưa đặt sau khi bạn đã sử dụng chúng cũng giúp, mặc dù thực hiện điều này cùng với phương pháp free() ở trên như được đề cập, vì unset() sẽ không xóa thông số vòng tròn theo cách khác.

+0

miễn phí() giúp ích rất nhiều, cảm ơn! –

0

Ngoài giá trị xem xét:

gc_collect_cycles - Lực lượng bộ sưu tập của bất kỳ chu kỳ rác hiện

+0

trước đó bạn nên bật gc => gc_enable() – kirugan

1

Tôi đã có cùng một vấn đề với việc làm PHP mẻ cho symfony - nếu họ chạy trong một thời gian dài và sử dụng rất nhiều dữ liệu họ có xu hướng phát bóng và thậm chí nếu tôi thực hiện một trình bao bọc đã gọi ra nhiều quy trình PHP riêng biệt, nó không giúp ích gì.

Vì lý do này, tôi đã viết lại các công việc hàng loạt lớn hơn với DBI của Perl và chúng đáng tin cậy và dễ quản lý.

Tôi không đề xuất đây là câu trả lời hay nhất, chỉ thông cảm và mang lại trải nghiệm của tôi. Có lẽ một cách để làm cho PHP hoạt động tốt hơn.

2

Rất tiếc, tôi biết đây là câu trả lời muộn nhưng có thể giúp ai đó.

Trình tiết kiệm bộ nhớ có khả năng lớn khác là đảm bảo chế độ gỡ lỗi của Symfony không được bật cho tác vụ đó.Trong một vài nhiệm vụ chạy dài, tôi đã thêm vào dòng này và nó giảm mức sử dụng RAM khoảng 40% ngay cả sau khi tôi đã tối ưu hóa những thứ như chế độ hydrat hóa.

sfConfig::set('sf_debug', false); 
4

Hãy thử điều này:

Doctrine_Manager::connection()->setAttribute(Doctrine_Core::ATTR_AUTO_FREE_QUERY_OBJECTS, true); 

như đã đề cập trên

php/symfony/doctrine memory leak?

trả lời từ Jordan Feldstein không phải của tôi.

4

Một gợi ý khác để giảm dung lượng bộ nhớ được sử dụng bên trong một tác vụ là vô hiệu hóa lược tả truy vấn. Một số lượng lớn các truy vấn có xu hướng làm cho tác vụ sử dụng nhiều bộ nhớ hơn.

Để làm như vậy tạo ra một môi trường công việc mới trong tập tin cấu hình database.yml của bạn bằng cách thêm các dòng sau:

task: 
    doctrine: 
    class: sfDoctrineDatabase 
    param: 
     profiler: false 

Sau đó thiết lập nhiệm vụ của bạn để chạy trong "nhiệm vụ" môi trường. Nó sẽ giúp giữ cho bộ nhớ sử dụng ổn định nếu truy vấn của bạn đang trong vòng lặp.

0

Cũng cố gắng giới hạn (chọn) trường trong truy vấn của bạn chỉ cho những trường bạn thực sự cần.

ví dụ sử dụng một cái gì đó như:

$query = self::createQuery("q")-> 
    ->select('id','title','price') 
    ... 

thay vì:

$query = self::createQuery("q")-> 
    ->select('*') 
    ... 
1

Thận trọng với fetchOne() trên học thuyết Query. cuộc gọi chức năng này sẽ không thêm "Giới hạn 1" trên SQL

Nếu bạn chỉ cần để có được một hồ sơ từ DB, hãy chắc chắn:

$q->limit(1)->fetchOne() 

Bộ nhớ sử dụng là rất lớn giảm trên bảng lớn.

Bạn có thể thấy fetchOne() sẽ tìm nạp từ DB dưới dạng bộ sưu tập trước rồi trả về phần tử đầu tiên.

public function fetchOne($params = array(), $hydrationMode = null) 
{ 
    $collection = $this->execute($params, $hydrationMode); 

    if (is_scalar($collection)) { 
     return $collection; 
    } 

    if (count($collection) === 0) { 
     return false; 
    } 

    if ($collection instanceof Doctrine_Collection) { 
     return $collection->getFirst(); 
    } else if (is_array($collection)) { 
     return array_shift($collection); 
    } 

    return false; 
} 
Các vấn đề liên quan