memory_get_peak_usage () với "mức sử dụng thực"


92

Nếu real_usageđối số được đặt thành truePHP DOCS nói rằng nó sẽ nhận được kích thước thực của bộ nhớ được cấp phát từ hệ thống. Nếu nó falsesẽ nhận được bộ nhớ được báo cáo bởiemalloc()

Một trong 2 tùy chọn này trả về giá thầu CPC bộ nhớ được cấp phát liên quan đến giá trị giới hạn bộ nhớ trong php.ini?

Tôi muốn biết kịch bản đã đạt đến giới hạn đó gần đến mức nào.


8
Tôi muốn hướng dẫn bạn đến một bài thuyết trình của Julien Pauli youtube.com/watch?v=sm1HUrnsxLI cho hội nghị php uk 2013, nơi anh ấy nói về cách bộ nhớ hoạt động bên trong PHP.
mpratt

Câu trả lời:


136

Ok, hãy kiểm tra điều này bằng cách sử dụng một tập lệnh đơn giản:

ini_set('memory_limit', '1M');
$x = '';
while(true) {
  echo "not real: ".(memory_get_peak_usage(false)/1024/1024)." MiB\n";
  echo "real: ".(memory_get_peak_usage(true)/1024/1024)." MiB\n\n";
  $x .= str_repeat(' ', 1024*25); //store 25kb more to string
}

Đầu ra:

not real: 0.73469543457031 MiB
real: 0.75 MiB

not real: 0.75910949707031 MiB
real: 1 MiB

...

not real: 0.95442199707031 MiB
real: 1 MiB

not real: 0.97883605957031 MiB
real: 1 MiB

PHP Fatal error:  Allowed memory size of 1048576 bytes exhausted (tried to allocate 793601 bytes) in /home/niko/test.php on line 7

Có vẻ như việc sử dụng thực sự là bộ nhớ được cấp phát từ hệ thống - bộ nhớ này dường như được phân bổ trong các nhóm lớn hơn mức cần thiết hiện tại của tập lệnh. (Tôi đoán vì lý do hiệu suất). Đây cũng là bộ nhớ mà tiến trình php sử dụng.

Việc $real_usage = falsesử dụng là mức sử dụng bộ nhớ mà bạn thực sự đã sử dụng trong tập lệnh của mình, không phải là lượng bộ nhớ thực được cấp phát bởi trình quản lý bộ nhớ của Zend.

Đọc câu hỏi này để biết thêm thông tin.

Tóm lại: để đạt được mức giới hạn bộ nhớ của bạn, hãy sử dụng $real_usage = true


5
Công cụ Zend phân bổ bộ nhớ theo khối 256K. Giá trị "sử dụng thực" là tổng của tất cả các phần này. Đó thực sự là giá trị sử dụng để kích hoạt các lỗi kiệt bộ nhớ: if (segment_size < true_size || heap->real_size + segment_size > heap->limit) { /* Memory limit overflow */.
cleong

2
Giá trị "không thực" là tổng số byte được yêu cầu bởi các lệnh gọi tới emalloc(cộng với byte cho tiêu đề và căn chỉnh bộ nhớ). Nó không phản ánh bộ nhớ bị lãng phí do các khối không phù hợp với không gian còn lại trong các phân đoạn đã được cấp phát. Nếu bạn thay đổi ví dụ của mình thành phân bổ (1024 * 256) byte và giới hạn 2M, sự khác biệt của hai sẽ trở nên rõ ràng hơn.
cleong

@Niko, Tại sao bạn lại sử dụng memory_get_peak_usage thay vì memory_get_usage? Chúng ta có nên gc_disable () và sử dụng memory_get_usage để có kết quả chính xác hơn không?
Pacerier

@Pacerier câu hỏi là để có được cách gần với giới hạn kịch bản là - cho rằng làm cho đỉnh cao cảm nhận được tôi muốn nói
Niko Sams

4
Như @cleong đã giải thích, câu trả lời này thực sự sai, bất chấp tất cả các phiếu ủng hộ. Các memory_get_usage(true)lợi nhuận giá trị mà nên được so sánh với memory_limit. Ví dụ được đưa ra trong câu trả lời quá đơn giản vì không có bộ nhớ "lãng phí" ". Điều xảy ra là bộ nhớ được cấp phát" thực "cần được tăng từ" 1 MiB "lên" 1,25 MiB "và đó là điều gây ra lỗi nghiêm trọng . tôi có một kịch bản hàng loạt phức tạp với giới hạn bộ nhớ của 120 MiB có "không thật" phân bổ bộ nhớ chỉ có "80 MiB" khi nó được hủy bỏ vì "thực sự" cấp phát bộ nhớ đạt đến giới hạn.
Martin Prikryl

36

Giới thiệu

Bạn nên sử dụng memory_get_usage(false)vì những gì bạn muốn là bộ nhớ được sử dụng chứ không phải bộ nhớ được cấp phát.

Có gì khác biệt

Bạn Google Mailcó thể đã phân bổ 25MBdung lượng lưu trữ cho bạn nhưng không có nghĩa đó là những gì bạn đã sử dụng vào lúc này.

Đây chính xác là những gì tài liệu PHP đã nói

Đặt giá trị này thành TRUE để nhận kích thước thực của bộ nhớ được cấp phát từ hệ thống. Nếu không được đặt hoặc FALSE, chỉ bộ nhớ được sử dụng bởi emalloc () được báo cáo.

Cả hai đối số sẽ trả về bộ nhớ được cấp phát liên quan đến giới hạn bộ nhớ nhưng sự khác biệt chính là:

memory_get_usage(false)cung cấp cho bộ nhớ được sử dụng bởi emalloc()trong khi memory_get_usage(true)trả về cột mốc có thể được minh họa ở đây Memory Mile Store

Tôi muốn biết kịch bản đã đạt đến giới hạn đó gần đến mức nào.

Điều đó sẽ mất một số phép toán và có thể chỉ hoạt động trong các vòng lặp hoặc các trường hợp sử dụng cụ thể. Tại sao tôi lại nói như vậy?

Tưởng tượng

ini_set('memory_limit', '1M');
$data = str_repeat(' ', 1024 * 1024);

The above script would fail before you even get the chance to start start checking memory.

Theo như tôi biết, cách duy nhất tôi có thể kiểm tra bộ nhớ được sử dụng cho một biến hoặc phần cụ thể của PHP là:

$start_memory = memory_get_usage();
$foo = "Some variable";
echo memory_get_usage() - $start_memory;

Xem phần Giải thích , nhưng nếu bạn đang ở trong một hàm lặp hoặc hàm đệ quy, bạn có thể sử dụng mức sử dụng bộ nhớ tối đa để ước tính một cách an toàn khi nào đạt đến tốc độ bộ nhớ.

Thí dụ

ini_set('memory_limit', '1M');

$memoryAvailable = filter_var(ini_get("memory_limit"), FILTER_SANITIZE_NUMBER_INT);
$memoryAvailable = $memoryAvailable * 1024 * 1024;

$peekPoint = 90; // 90%

$memoryStart = memory_get_peak_usage(false);
$memoryDiff = 0;

// Some stats
$stat = array(
        "HIGHEST_MEMORY" => 0,
        "HIGHEST_DIFF" => 0,
        "PERCENTAGE_BREAK" => 0,
        "AVERAGE" => array(),
        "LOOPS" => 0
);

$data = "";
$i = 0;
while ( true ) {
    $i ++;

    // Get used memory
    $memoryUsed = memory_get_peak_usage(false);

    // Get Diffrence
    $memoryDiff = $memoryUsed - $memoryStart;

    // Start memory Usage again
    $memoryStart = memory_get_peak_usage(false);

    // Gather some stats
    $stat['HIGHEST_MEMORY'] = $memoryUsed > $stat['HIGHEST_MEMORY'] ? $memoryUsed : $stat['HIGHEST_MEMORY'];
    $stat['HIGHEST_DIFF'] = $memoryDiff > $stat['HIGHEST_DIFF'] ? $memoryDiff : $stat['HIGHEST_DIFF'];
    $stat['AVERAGE'][] = $memoryDiff;
    $stat['LOOPS'] ++;
    $percentage = (($memoryUsed + $stat['HIGHEST_DIFF']) / $memoryAvailable) * 100;

    // var_dump($percentage, $memoryDiff);

    // Stop your scipt
    if ($percentage > $peekPoint) {

        print(sprintf("Stoped at: %0.2f", $percentage) . "%\n");
        $stat['AVERAGE'] = array_sum($stat['AVERAGE']) / count($stat['AVERAGE']);
        $stat = array_map(function ($v) {
            return sprintf("%0.2f", $v / (1024 * 1024));
        }, $stat);
        $stat['LOOPS'] = $i;
        $stat['PERCENTAGE_BREAK'] = sprintf("%0.2f", $percentage) . "%";
        echo json_encode($stat, 128);
        break;
    }

    $data .= str_repeat(' ', 1024 * 25); // 1kb every time
}

Đầu ra

Stoped at: 95.86%
{
    "HIGHEST_MEMORY": "0.71",
    "HIGHEST_DIFF": "0.24",
    "PERCENTAGE_BREAK": "95.86%",
    "AVERAGE": "0.04",
    "LOOPS": 11
}

Bản thử trực tiếp

Điều này vẫn có thể thất bại

Nó có thể không thành công vì sau if ($percentage > $peekPoint) { đó vẫn còn thêm để thực hiện tác vụ bổ sung và cũng tiêu tốn bộ nhớ

        print(sprintf("Stoped at: %0.2f", $percentage) . "%\n");
        $stat['AVERAGE'] = array_sum($stat['AVERAGE']) / count($stat['AVERAGE']);
        $stat = array_map(function ($v) {
            return sprintf("%0.2f", $v / (1024 * 1024));
        }, $stat);
        $stat['LOOPS'] = $i;
        $stat['PERCENTAGE_BREAK'] = sprintf("%0.2f", $percentage) . "%";
        echo json_encode($stat, 128);
        break;

If the memory to process this request is grater than the memory available the script would fail.

Phần kết luận

Nó không phải là một giải pháp hoàn hảo nhưng hãy kiểm tra bộ nhớ trong khoảng thời gian và nếu nó vượt quá mức nhìn thấy (ví dụ: 90%) exitngay lập tức và để lại những thứ ưa thích


memory_limittùy chọn về đống? hay ngăn xếp?
Yousha Aleayoub

Điều gì sẽ xảy ra nếu tôi có hai tập lệnh song song hoặc nhiều yêu cầu, hàm memory_get_usage () trả về bộ nhớ được sử dụng cho tất cả các tập lệnh đó được thực thi cùng một lúc hoặc chỉ tập lệnh thực sự?
Mohammed Yassine CHABLI

7

real_usagebáo cáo sai về việc sử dụng mà tập lệnh của bạn đã sử dụng . Điều này sẽ chính xác hơn trong số hai.

real_usagetrue báo cáo bộ nhớ được phân bổ cho tập lệnh của bạn. Đây sẽ là mức cao hơn trong hai.

Tôi có thể sẽ sử dụng truenếu tôi đang cố gắng so sánh, vì tập lệnh của bạn sẽ không bao giờ được cấp phát nhiều hơn giới hạn bộ nhớ và sẽ tiếp tục chạy miễn là nó (cộng với tất cả các tập lệnh khác) không vượt quá mức sử dụng đó.


1
Nó hoàn toàn ngược lại: falselà bộ nhớ mà script được sử dụng , truelà bộ nhớ được cấp phát .
Benjamin

1
@Benjamin Vâng, không hiểu sao tôi lại nhầm lẫn một cách mù quáng. Ừm, cố định rồi.
Glitch Desire,

2

theo PHP memory_get_usage

real_usage

Đặt giá trị này thành TRUE để nhận tổng bộ nhớ được phân bổ từ hệ thống, bao gồm cả các trang không sử dụng. Nếu không được đặt hoặc FALSE, chỉ bộ nhớ đã sử dụng được báo cáo.

vì vậy để lấy bộ nhớ được sử dụng bởi script của bạn, bạn nên sử dụng memory_get_usage () vì real_usage mặc định là false.

nếu bạn muốn lấy bộ nhớ được hệ thống cấp phát nhưng không quan tâm đến dung lượng thực sự đã được sử dụng, hãy sử dụng memory_get_usage (true);


0
<!-- Print CPU memory and load -->
<?php
$output = shell_exec('free');
$data = substr($output,111,19);
echo $data;
echo file_get_contents('/proc/loadavg');
$load = sys_getloadavg();
$res = implode("",$load);
echo $res;
?>

2
Chào mừng bạn đến với Stackoverflow! bạn có thể vui lòng cho chúng tôi biết câu trả lời là gì không? Không chỉ mã mà còn cả cách bạn tìm ra cách sửa câu hỏi. Cảm ơn!
Gilles Heinesch

Mặc dù câu trả lời của bạn có thể cung cấp một số thông tin hữu ích tiềm năng, nhưng nó không liên quan đến câu hỏi đang được hỏi. Bạn có thể muốn giải thích câu trả lời của bạn liên quan như thế nào đến câu hỏi đang được hỏi.
Moritur
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.