memory_get_peak_usage () ด้วย“ การใช้งานจริง”


94

หากreal_usageอาร์กิวเมนต์ถูกตั้งค่าtrueเป็น PHP DOCS บอกว่าจะได้รับขนาดจริงของหน่วยความจำที่จัดสรรจากระบบ ถ้ามันfalseจะได้รับหน่วยความจำรายงานโดยemalloc()

ตัวเลือกใดตัวเลือกหนึ่งใน 2 ตัวนี้ส่งกลับค่าสูงสุด หน่วยความจำที่จัดสรรโดยสัมพันธ์กับค่าขีด จำกัด หน่วยความจำใน php.ini?

ฉันต้องการทราบว่าสคริปต์ใกล้ถึงขีด จำกัด นั้นแค่ไหน


9
ฉันอยากจะแนะนำให้คุณนำเสนอโดย Julien Pauli youtube.com/watch?v=sm1HUrnsxLIสำหรับการประชุม php uk 2013 ซึ่งเขาพูดถึงวิธีการทำงานของหน่วยความจำภายใน PHP
mpratt

คำตอบ:


139

โอเคลองทดสอบโดยใช้สคริปต์ง่ายๆ:

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
}

เอาท์พุต:

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

ดูเหมือนว่าการใช้งานจริงเป็นหน่วยความจำที่จัดสรรจากระบบซึ่งดูเหมือนว่าจะได้รับการจัดสรรในที่เก็บข้อมูลขนาดใหญ่กว่าที่สคริปต์ต้องการในปัจจุบัน (ฉันเดาด้วยเหตุผลด้านประสิทธิภาพ) นี่คือหน่วยความจำที่กระบวนการ php ใช้

การ$real_usage = falseใช้งานคือการใช้หน่วยความจำที่คุณใช้จริงในสคริปต์ของคุณไม่ใช่จำนวนหน่วยความจำจริงที่จัดสรรโดยผู้จัดการหน่วยความจำของ Zend

อ่านคำถามนี้สำหรับข้อมูลเพิ่มเติม

กล่าวโดยย่อ: เพื่อให้คุณเข้าใกล้ขีด จำกัด หน่วยความจำมากแค่ไหนให้ใช้ $real_usage = true


5
เอ็นจิ้น Zend จัดสรรหน่วยความจำเป็นหน่วยความจำ 256K ค่า "การใช้งานจริง" คือผลรวมของชิ้นส่วนเหล่านี้ทั้งหมด if (segment_size < true_size || heap->real_size + segment_size > heap->limit) { /* Memory limit overflow */ที่จริงค่าที่ใช้ในการเกิดข้อผิดพลาดของหน่วยความจำอ่อนเพลีย:
เคลียร์

2
ค่า "ไม่จริง" คือผลรวมของจำนวนไบต์ที่ร้องขอโดยการเรียกไปยังemalloc(บวกไบต์สำหรับส่วนหัวและการจัดแนวหน่วยความจำ) มันไม่ได้สะท้อนถึงการสูญเสียหน่วยความจำเนื่องจากบล็อกไม่พอดีกับพื้นที่ที่เหลืออยู่ในเซ็กเมนต์ที่จัดสรรไว้แล้ว หากคุณเปลี่ยนตัวอย่างเพื่อจัดสรร (1024 * 256) ไบต์และขีด จำกัด 2M ความแตกต่างของสองจะชัดเจนมากขึ้น
เคลียร์

@ นิโกะทำไมคุณถึงใช้ memory_get_peak_usage แทน memory_get_usage? เราไม่ควร gc_disable () และใช้ memory_get_usage เพื่อให้ได้ผลลัพธ์ที่แม่นยำยิ่งขึ้นใช่หรือไม่?
Pacerier

@Pacerier คำถามคือการเข้าใกล้ขีด จำกัด ของสคริปต์ - สำหรับจุดสูงสุดนั้นสมเหตุสมผลฉันจะพูดว่า
Niko Sams

4
ตามที่ @cleong ได้อธิบายไว้คำตอบนี้ไม่ถูกต้องแม้จะมีการโหวตเพิ่มขึ้นทั้งหมด มูลค่าผลตอบแทนที่ควรเมื่อเทียบกับmemory_get_usage(true) memory_limitตัวอย่างที่ให้ไว้ในคำตอบนั้นง่ายเกินไปเนื่องจากไม่มีหน่วยความจำ "สูญเปล่า" สิ่งที่เกิดขึ้นคือหน่วยความจำที่จัดสรร "จริง" จะต้องเพิ่มขึ้นจาก "1 MiB" เป็น "1.25 MiB" และนั่นคือสิ่งที่ทำให้เกิดข้อผิดพลาดร้ายแรง . ฉันมีสคริปต์แบตช์ที่ซับซ้อนซึ่งมีหน่วยความจำ จำกัด 120 MiB ซึ่งมีหน่วยความจำที่จัดสรร "ไม่จริง" เพียง "80 MiB" เมื่อถูกยกเลิกเนื่องจากหน่วยความจำที่จัดสรร "จริง" ถึงขีด จำกัด
Martin Prikryl

37

บทนำ

คุณควรใช้memory_get_usage(false)เพราะสิ่งที่คุณต้องการคือหน่วยความจำที่ใช้ไม่ใช่หน่วยความจำที่จัดสรร

อะไรคือความแตกต่าง

คุณGoogle Mailอาจจัดสรร25MBพื้นที่เก็บข้อมูลให้คุณ แต่ไม่ได้หมายความว่าเป็นสิ่งที่คุณใช้ในขณะนี้

นี่คือสิ่งที่เอกสาร PHP บอก

ตั้งค่านี้เป็น TRUE เพื่อรับขนาดจริงของหน่วยความจำที่จัดสรรจากระบบ หากไม่ได้ตั้งค่าหรือ FALSE จะมีการรายงานเฉพาะหน่วยความจำที่ใช้โดย emalloc ()

อาร์กิวเมนต์ทั้งสองจะส่งคืนหน่วยความจำที่จัดสรรโดยสัมพันธ์กับขีด จำกัด หน่วยความจำ แต่ข้อแตกต่างหลักคือ:

memory_get_usage(false)ให้หน่วยความจำที่ใช้emalloc()ในขณะที่memory_get_usage(true)ส่งกลับเหตุการณ์สำคัญซึ่งสามารถสาธิตได้ที่นี่Memory Mile Store

ฉันต้องการทราบว่าสคริปต์ใกล้ถึงขีด จำกัด นั้นแค่ไหน

ซึ่งจะต้องใช้คณิตศาสตร์บางส่วนและอาจใช้ได้เฉพาะในลูปหรือกรณีการใช้งานที่เฉพาะเจาะจงเท่านั้น ทำไมฉันถึงพูดแบบนั้น?

ลองนึกภาพ

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.

เท่าที่ฉันรู้วิธีเดียวที่ฉันสามารถตรวจสอบหน่วยความจำที่ใช้สำหรับตัวแปรหรือส่วนเฉพาะของ PHP คือ:

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

ดูคำอธิบายแต่ถ้าคุณอยู่ในฟังก์ชั่นวนซ้ำหรือวนซ้ำคุณสามารถใช้การใช้หน่วยความจำสูงสุดเพื่อประเมินอย่างปลอดภัยเมื่อหน่วยความจำจะมาถึง

ตัวอย่าง

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
}

เอาต์พุต

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

การสาธิตสด

สิ่งนี้อาจยังล้มเหลว

มันอาจจะล้มเหลวเพราะหลังจาก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;

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

สรุป

ไม่ใช่วิธีการแก้ปัญหาที่สมบูรณ์แบบ แต่ตรวจสอบหน่วยความจำในช่วงเวลาและหากมีการมองเกิน (เช่น 90%) ใน exitทันทีและปล่อยให้สิ่งที่น่าสนใจ


เป็นmemory_limitตัวเลือกที่เกี่ยวกับกอง? หรือกอง?
Yousha Aleayoub

จะเกิดอะไรขึ้นถ้าฉันมีสองสคริปต์ในแบบขนานหรือหลายคำขอให้ฟังก์ชัน memory_get_usage () ส่งคืนหน่วยความจำที่ใช้สำหรับสคริปต์ทั้งหมดที่ดำเนินการในเวลาเดียวกันหรือเฉพาะสคริปต์จริง
Mohammed Yassine CHABLI

7

real_usageรายงานเท็จการใช้งานสคริปต์ของคุณใช้ นี่จะเป็นความแม่นยำมากขึ้นของทั้งสอง

real_usagetrue รายงานหน่วยความจำที่จัดสรรให้กับสคริปต์ของคุณ นี่จะสูงกว่าของทั้งสอง

ฉันอาจจะใช้trueถ้าฉันพยายามเปรียบเทียบเนื่องจากสคริปต์ของคุณจะไม่ถูกจัดสรรเกินขีด จำกัด หน่วยความจำและจะทำงานต่อไปตราบเท่าที่มัน (รวมถึงสคริปต์อื่น ๆ ทั้งหมด) ไม่เกินการใช้งานนั้น


1
มันตรงข้าม: falseเป็นหน่วยความจำสคริปต์ที่ใช้ , trueเป็นหน่วยความจำที่จัดสรร
Benjamin

1
@ เบ็นจามินใช่ไม่แน่ใจว่าทำไมฉันถึงเข้าใจผิดแบบสุ่มสี่สุ่มห้า อืมแก้ไขแล้ว
Glitch Desire

2

ตาม PHP memory_get_usage

real_usage

ตั้งค่านี้เป็น TRUE เพื่อรับหน่วยความจำทั้งหมดที่จัดสรรจากระบบรวมถึงหน้าที่ไม่ได้ใช้ หากไม่ได้ตั้งค่าไว้หรือ FALSE จะมีการรายงานเฉพาะหน่วยความจำที่ใช้เท่านั้น

ดังนั้นเพื่อให้ได้หน่วยความจำที่ใช้โดยสคริปต์ของคุณคุณควรใช้ memory_get_usage () เนื่องจากค่าเริ่มต้น real_usage เป็นเท็จ

หากคุณต้องการรับหน่วยความจำที่ระบบจัดสรร แต่ไม่สนใจว่าจะใช้จริงมากแค่ไหนให้ใช้ 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
ยินดีต้อนรับสู่ Stackoverflow! คุณช่วยบอกเราได้ไหมว่าคำตอบคืออะไร? ไม่ใช่แค่รหัส แต่ยังรวมถึงวิธีการแก้ไขคำถามด้วย ขอบคุณ!
Gilles Heinesch

แม้ว่าคำตอบของคุณอาจให้ข้อมูลที่เป็นประโยชน์ แต่ก็ไม่เกี่ยวข้องกับคำถามที่ถูกถาม คุณอาจต้องการอธิบายว่าคำตอบของคุณเกี่ยวข้องกับคำถามที่ถูกถามอย่างไร
Moritur
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.