memory_get_peak_usage () dengan “penggunaan nyata”

94

Jika real_usageargumen disetel ke truePHP DOCS, katakan itu akan mendapatkan ukuran sebenarnya dari memori yang dialokasikan dari sistem. Jika itu falseakan mendapatkan memori yang dilaporkan olehemalloc()

Manakah dari 2 opsi ini yang mengembalikan nilai maks. memori yang dialokasikan relatif terhadap nilai batas memori di php.ini?

Saya ingin tahu seberapa dekat skrip mencapai batas itu.

thelolcat
sumber
8
Saya ingin menunjukkan presentasi oleh Julien Pauli youtube.com/watch?v=sm1HUrnsxLI untuk konferensi php uk 2013, di mana dia berbicara tentang cara kerja memori di dalam PHP.
mpratt

Jawaban:

138

Oke, mari kita uji ini menggunakan skrip sederhana:

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
}

Keluaran:

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

Sepertinya penggunaan sebenarnya adalah memori yang dialokasikan dari sistem - yang tampaknya dialokasikan dalam bucket yang lebih besar daripada yang saat ini dibutuhkan oleh skrip. (Saya kira karena alasan kinerja). Ini juga merupakan memori yang digunakan proses php.

The $real_usage = falsepenggunaan adalah penggunaan memori Anda benar-benar digunakan dalam naskah Anda, bukan jumlah aktual memori yang dialokasikan oleh manajer memori Zend.

Baca pertanyaan ini untuk informasi lebih lanjut.

Singkatnya: untuk mengetahui seberapa dekat Anda dengan batas memori, gunakan $real_usage = true

Niko Sams
sumber
5
Mesin Zend mengalokasikan memori dalam 256K potongan. Nilai "penggunaan nyata" adalah jumlah dari semua potongan ini. Itu sebenarnya nilai yang digunakan untuk memicu kesalahan kelelahan memori: if (segment_size < true_size || heap->real_size + segment_size > heap->limit) { /* Memory limit overflow */.
cleong
2
Nilai "tidak nyata" adalah jumlah dari jumlah byte yang diminta oleh panggilan ke emalloc(ditambah byte untuk header dan penyelarasan memori). Itu tidak mencerminkan memori yang terbuang karena blok tidak pas dengan ruang yang tersisa di segmen yang sudah dialokasikan. Jika Anda mengubah contoh Anda untuk mengalokasikan (1024 * 256) byte dan batas 2M, perbedaan dua akan menjadi lebih jelas.
cleong
@ Niko, Mengapa Anda menggunakan memory_get_peak_usage daripada memory_get_usage? Bukankah kita harus gc_disable () dan menggunakan memory_get_usage untuk mendapatkan hasil yang lebih akurat?
Pacerier
@Pacerier pertanyaannya adalah untuk mendapatkan seberapa dekat batas skrip - untuk puncak itu masuk akal menurut saya
Niko Sams
4
Seperti yang dijelaskan @cleong, jawaban ini sebenarnya salah, terlepas dari semua upvote. Nilai memory_get_usage(true)pengembalian yang harus dibandingkan memory_limit. Contoh yang diberikan dalam jawaban terlalu sederhana karena tidak ada "memori yang terbuang". Apa yang terjadi adalah bahwa memori yang dialokasikan "sebenarnya" perlu ditingkatkan dari "1 MiB" menjadi "1,25 MiB" dan itulah yang memicu kesalahan fatal Saya memiliki skrip batch kompleks dengan batas memori 120 MiB yang memiliki memori yang dialokasikan "tidak nyata" hanya "80 MiB" saat dibatalkan karena memori yang dialokasikan "sebenarnya" mencapai batas.
Martin Prikryl
37

pengantar

Anda harus menggunakan memory_get_usage(false)karena yang Anda inginkan adalah memori yang digunakan bukan memori yang dialokasikan.

Apa bedanya

Anda Google Mailmungkin telah mengalokasikan 25MBpenyimpanan untuk Anda tetapi itu tidak berarti itulah yang telah Anda gunakan saat ini.

Ini persis seperti yang dikatakan oleh dokumen PHP

Setel ini ke TRUE untuk mendapatkan ukuran sebenarnya dari memori yang dialokasikan dari sistem. Jika tidak disetel atau FALSE, hanya memori yang digunakan oleh emalloc () yang dilaporkan.

Kedua argumen tersebut akan mengembalikan memori yang dialokasikan relatif terhadap batas memori tetapi perbedaan utamanya adalah:

memory_get_usage(false)Berikan memori yang digunakan emalloc()saat memory_get_usage(true)mengembalikan tonggak yang bisa didemonstrasikan di sini Memory Mile Store

Saya ingin tahu seberapa dekat skrip mencapai batas itu.

Itu akan membutuhkan beberapa matematika dan mungkin hanya berfungsi dalam loop atau kasus penggunaan tertentu. Mengapa saya mengatakan seperti itu?

Membayangkan

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.

Sejauh yang saya tahu, satu-satunya cara saya dapat memeriksa memori yang digunakan untuk variabel atau bagian tertentu dari PHP adalah:

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

Lihat Penjelasan , tetapi jika Anda berada dalam fungsi loop atau rekursif, Anda dapat menggunakan penggunaan memori maksimum untuk memperkirakan dengan aman kapan intip memori akan tercapai.

Contoh

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
}

Keluaran

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

Demo Langsung

Ini mungkin masih gagal

Mungkin gagal karena setelah if ($percentage > $peekPoint) { ini masih menambah untuk melakukan tugas tambahan dengan juga memakan memori

        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.

Kesimpulan

Ini bukan solusi sempurna tetapi periksa memori pada interval dan jika melebihi mengintip (misalnya 90%) secara exitinstan dan tinggalkan barang mewah

Baba
sumber
Apakah memory_limitopsi tentang heap? atau tumpukan?
Yousha Aleayoub
bagaimana jika saya memiliki dua skrip secara paralel atau banyak permintaan, di fungsi memory_get_usage () mengembalikan memori yang digunakan untuk semua skrip yang dieksekusi dalam waktu yang sama atau hanya skrip yang sebenarnya?
Mohammed Yassine CHABLI
7

real_usagefalse melaporkan penggunaan skrip Anda yang digunakan . Ini akan menjadi yang lebih akurat dari keduanya.

real_usagetrue melaporkan memori yang dialokasikan ke skrip Anda. Ini akan menjadi yang lebih tinggi dari keduanya.

Saya mungkin akan menggunakan truejika saya mencoba membandingkan, karena skrip Anda tidak akan pernah dialokasikan lebih dari batas memori, dan akan terus berjalan selama itu (ditambah semua skrip lainnya) tidak melebihi penggunaan itu.

Glitch Desire
sumber
1
Justru sebaliknya: falseapakah memori yang digunakan skrip , trueadalah memori yang dialokasikan .
Benjamin
1
@Benjamin Ya, tidak yakin mengapa saya melakukan kesalahan yang begitu membabi buta. Umm, sudah diperbaiki.
Glitch Desire
2

sesuai PHP memory_get_usage

real_usage

Setel ini ke TRUE untuk mendapatkan total memori yang dialokasikan dari sistem, termasuk halaman yang tidak digunakan. Jika tidak diatur atau SALAH, hanya memori yang digunakan yang dilaporkan.

jadi untuk mendapatkan memori yang digunakan oleh skrip Anda, Anda harus menggunakan memory_get_usage () karena real_usage default adalah false.

jika Anda ingin mendapatkan memori yang dialokasikan oleh sistem tetapi tidak peduli berapa banyak yang sebenarnya digunakan, gunakan memory_get_usage (true);

Tofeeq
sumber
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;
?>
Rahul Rohewal
sumber
2
Selamat datang di Stackoverflow! bisa tolong beri tahu kami apa jawabannya? Bukan hanya kode tetapi juga bagaimana Anda menemukan cara untuk memperbaiki pertanyaan. Terima kasih!
Gilles Heinesch
Meskipun jawaban Anda mungkin memberikan beberapa informasi yang berpotensi berguna, itu tidak relevan dengan pertanyaan yang ditanyakan. Anda mungkin ingin menjelaskan bagaimana jawaban Anda berkaitan dengan pertanyaan yang diajukan.
Moritur