2013-04-17 22 views
26

Máy chủ chuyên dụng của tôi có RAM 32 GB và bộ nhớ chỉ tăng lên liên tục và tôi phải khởi động lại nó hàng ngày ngay bây giờ. Điều này khiến tôi tốn tiền và khách hàng.Cách tìm tập lệnh PHP nào bị rò rỉ bộ nhớ?

Tôi gặp khó khăn khi tìm nơi rò rỉ bộ nhớ. Tất cả tôi có thể tìm thấy trực tuyến là mọi người nói "Sử dụng xdebug" nhưng tôi đã không thể tìm thấy bất kỳ hướng dẫn xdebug về việc tìm kiếm rò rỉ bộ nhớ. Tôi đã thử in memory_get_usage trước và sau khi các cuộc gọi chức năng nhưng là đúng cách để làm điều đó?

Tôi có nhiều tập lệnh php đang chạy - một số từ khách truy cập, những người khác từ công việc cron - và tôi cần tìm (những) người nào đang rò rỉ bộ nhớ và sửa ASAP nhưng tôi thậm chí không biết cách xác định xem một chức năng cụ thể là bộ nhớ bị rò rỉ hay không.

Tôi đã thử in memory_get_usage trước khi gọi hàm và sau đó, và nó tăng lên, nhưng sau đó nếu tôi gọi hàm nhiều lần, nó sẽ không xuất hiện nữa. Ai đó có thể vui lòng giải thích điều này và cho tôi biết làm thế nào tôi có thể chỉ đơn giản và dễ dàng cho biết nếu một chức năng PHP có một rò rỉ bộ nhớ?

+0

Tôi đã cân nhắc thực hiện điều đó ... sao chép toàn bộ nội dung sang một máy chủ khác và chỉ chạy một phần tại một thời điểm và xem nguyên nhân gây ra nó. Tốn kém và tốn thời gian mặc dù ... Không có cách nào để đơn vị kiểm tra bộ nhớ trong PHP? – Guy

+0

Tôi không biết. Tôi cũng tò mò. Tôi đã bình chọn cho bạn và có thể cả hai chúng tôi sẽ tìm ra. –

+0

Tôi đồng ý với @ TomášZato.Bạn có thể sử dụng một kịch bản 'auto_append_file' và' memory_get_ * 'để ghi lại tất cả các kịch bản của bạn và xem ra các kịch bản nặng. – metadings

Trả lời

19

Bạn có thể làm nhiều việc khác nhau, nhưng trước tiên bạn nên cố gắng tránh việc tạo rò rỉ bộ nhớ ngay từ đầu.

Hãy để tôi làm rõ: PHP là một ngôn ngữ kịch bản và nó không được thiết kế cho các tập lệnh chạy dài, do đó quản lý bộ nhớ không phải là tốt nhất trên thị trường. Nhưng tại sao nó nên được? Mục đích của nó là được gọi trên một mức yêu cầu để phạm vi hoạt động của nó khá nhỏ (không quá 2 - 3 giây). Mọi thứ khác nên được đặt trong nền.

Tôi có thể làm gì để chống lại rò rỉ bộ nhớ?

  1. Nếu bạn đang ở phiên bản dưới 5.4 bạn cần phải quan tâm đến tham chiếu vòng kết nối vì không phải là rác thu thập được.

  2. Nếu bạn cần tập lệnh chạy liên tục, bạn có thể nghĩ về một cách tiếp cận khác. Hãy thử triển khai while(true), nhưng quấn supervisor (http://supervisord.org) xung quanh tập lệnh của bạn và để nó được gọi sau khi nó kết thúc. Bằng cách đó bạn đảm bảo 100% bạn không bao giờ bị rò rỉ bộ nhớ.

  3. Bạn có thể sử dụng xdebug để cấu hình từng tập lệnh của mình và tìm hiểu, nơi tiêu thụ nhiều bộ nhớ.

  4. Bạn có thể triển khai trình phá hủy để hủy đặt tất cả các tham chiếu nếu lớp không còn là nhu cầu nữa.

    public function __destruct(){ 
        $this->cleanup(); 
    } 
    
    public function cleanup() { 
        //cleanup everything from attributes 
        foreach (get_class_vars(__CLASS__) as $clsVar => $_) { 
         unset($this->$clsVar); 
        } 
    
        //cleanup all objects inside data array 
        if (is_array($this->_data)) { 
         foreach ($this->_data as $value) { 
          if (is_object($value) && method_exists($value, 'cleanUp')) { 
           $value->cleanUp(); 
          } 
         } 
        } 
    } 
    
  5. Đọc qua tài liệu PHP liên quan đến thu gom rác thải http://us3.php.net/manual/en/features.gc.php

  6. Tránh biến toàn cầu, bởi vì đó là những không bao giờ thu gom rác thải và cần phải được unset một cách rõ ràng. Nếu bạn đang sử dụng một khung như ZF hoặc Symfony mà có thể không được, vì bạn sẽ phá vỡ chức năng nếu bạn làm.

Cuối cùng nhưng không kém phần quan Tôi muốn nhấn mạnh một lần nữa , PHP là không phù hợp cho các kịch bản chạy dài! Nếu bạn có việc cần làm, cần phải chạy liên tục, bạn không nên làm sụp đổ đầu của bạn với rò rỉ bộ nhớ trong PHP, nhưng dành thời gian để học một ngôn ngữ phức tạp hơn như JAVA hoặc C#.

+0

Còn về các vars được tham chiếu thì sao? –

1

Tôi không phải là một chuyên gia về sử dụng bộ nhớ, nhưng có lẽ phương pháp này sẽ giúp bạn phát hiện các kịch bản có vấn đề:

Nhận thông tin: 1. Sử dụng truy cập apache file log 2. Tạo sử dụng bộ nhớ của riêng bạn tệp nhật ký (http://www.webhostingtalk.com/showthread.php?t=617742)

Kiểm tra thời gian khi mức sử dụng bộ nhớ tăng lên và so sánh với nhật ký truy cập apache.

Ít nhất nó sẽ cung cấp cho bạn thông tin cho dù mức sử dụng tăng chậm và không đổi hoặc nếu nó bắt đầu tại một điểm nhất định.

Chúc may mắn!

5

tôi thấy phương pháp mà hoạt động khá tốt cho tôi:

  1. Cài đặt "php-memprof" gia hạn. Trong bạn có thể Ubuntu chạy:

    sudo pecl install memprof

  2. Cài đặt "google-perftools". Một lần nữa cho Ubuntu:

    sudo apt-get install google-perftools

  3. Thêm mã này vào đầu của kịch bản của bạn:

    if (function_exists('memprof_enable')) { 
        memprof_enable(); 
    } 
    
  4. Và nơi aroud này là bạn expexct để tìm rò rỉ bộ nhớ:

    if (function_exists("memprof_dump_pprof")) 
    { 
        $time = microtime(true); 
        $f = fopen("/tmp/profile_$time.heap", "w"); 
        memprof_dump_pprof($f); 
        fclose($f); 
        echo "Memory profile dumped. "; 
    } 
    

    Trong trường hợp của tôi, nó ở trong chu kỳ lớn cứ 100 lần chạy.

  5. Run google-pprof bộ nhớ so sánh 2 bãi:

    google-pprof --web --base=/tmp/profile_17.heap /tmp/profile_18.heap 
    

    này sẽ mở ra hình ảnh svg như thế này trong trình duyệt của bạn:

    sample from doc

    Mô tả các con số và tên bên trong bạn có thể tìm thấy trong gperftools documentation

P.S. Sửa lỗi rò rỉ trên cấp độ php sẽ không đảm bảo với bạn rằng không có rò rỉ bộ nhớ trong thông dịch viên. Trong trường hợp của tôi, tôi kết thúc bằng việc khởi động lại sctipt trong thời gian dài hơn.

+0

Cách khắc phục? 'Không nhận được số biểu tượng từ http: /// pprof/symbol' – user2264941

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