以 KB 或 MB 取得記憶體使用量
<?php
function convert($size)
{
$unit=array('b','kb','mb','gb','tb','pb');
return @round($size/pow(1024,($i=floor(log($size,1024)))),2).' '.$unit[$i];
}
echo convert(memory_get_usage(true)); // 123 kb
?>
(PHP 4 >= 4.3.2, PHP 5, PHP 7, PHP 8)
memory_get_usage — 傳回配置給 PHP 的記憶體數量
注意事項:
PHP 並不會追蹤非由
emalloc()
所配置的記憶體。
回傳記憶體使用量,單位為位元組。
範例 #1 memory_get_usage() 範例
<?php
// 這只是一個範例,以下的數字會
// 根據您的系統而有所不同
echo memory_get_usage() . "\n"; // 36640
$a = str_repeat("Hello", 4242);
echo memory_get_usage() . "\n"; // 57960
unset($a);
echo memory_get_usage() . "\n"; // 36744
?>
以 KB 或 MB 取得記憶體使用量
<?php
function convert($size)
{
$unit=array('b','kb','mb','gb','tb','pb');
return @round($size/pow(1024,($i=floor(log($size,1024)))),2).' '.$unit[$i];
}
echo convert(memory_get_usage(true)); // 123 kb
?>
請注意,KB、MB 等的正式 IEC 字首分別為 KiB、MiB、TiB 等。
請見 http://en.wikipedia.org/wiki/Tebibyte
乍看之下,這聽起來像是「搞什麼?大家都知道,我們指的是 1024 而不是 1000,而且差異不大,所以呢?」。但大約 10 年後,硬碟的大小(以及上面的檔案)將達到 PB 的限制,屆時 PB 和 PiB 之間的差異將會非常巨大。
最好現在就習慣它 :)
memory_get_usage() 僅用於擷取分配給 PHP(或您正在執行的腳本)的記憶體。但直覺上,許多人期望根據函數名稱取得系統的記憶體使用量。
因此,如果您需要整體記憶體使用量,以下函數可能會有幫助。它會以百分比(不含百分比符號)或位元組為單位擷取記憶體使用量,方法是返回一個包含系統可用記憶體和總記憶體的陣列。已在 Windows (7) 和 Linux(在 Raspberry Pi 2 上)測試過
<?php
// Returns used memory (either in percent (without percent sign) or free and overall in bytes)
function getServerMemoryUsage($getPercentage=true)
{
$memoryTotal = null;
$memoryFree = null;
if (stristr(PHP_OS, "win")) {
// Get total physical memory (this is in bytes)
$cmd = "wmic ComputerSystem get TotalPhysicalMemory";
@exec($cmd, $outputTotalPhysicalMemory);
// Get free physical memory (this is in kibibytes!)
$cmd = "wmic OS get FreePhysicalMemory";
@exec($cmd, $outputFreePhysicalMemory);
if ($outputTotalPhysicalMemory && $outputFreePhysicalMemory) {
// Find total value
foreach ($outputTotalPhysicalMemory as $line) {
if ($line && preg_match("/^[0-9]+\$/", $line)) {
$memoryTotal = $line;
break;
}
}
// Find free value
foreach ($outputFreePhysicalMemory as $line) {
if ($line && preg_match("/^[0-9]+\$/", $line)) {
$memoryFree = $line;
$memoryFree *= 1024; // convert from kibibytes to bytes
break;
}
}
}
}
else
{
if (is_readable("/proc/meminfo"))
{
$stats = @file_get_contents("/proc/meminfo");
if ($stats !== false) {
// Separate lines
$stats = str_replace(array("\r\n", "\n\r", "\r"), "\n", $stats);
$stats = explode("\n", $stats);
// Separate values and find correct lines for total and free mem
foreach ($stats as $statLine) {
$statLineData = explode(":", trim($statLine));
//
// Extract size (TODO: It seems that (at least) the two values for total and free memory have the unit "kB" always. Is this correct?
//
// Total memory
if (count($statLineData) == 2 && trim($statLineData[0]) == "MemTotal") {
$memoryTotal = trim($statLineData[1]);
$memoryTotal = explode(" ", $memoryTotal);
$memoryTotal = $memoryTotal[0];
$memoryTotal *= 1024; // convert from kibibytes to bytes
}
// Free memory
if (count($statLineData) == 2 && trim($statLineData[0]) == "MemFree") {
$memoryFree = trim($statLineData[1]);
$memoryFree = explode(" ", $memoryFree);
$memoryFree = $memoryFree[0];
$memoryFree *= 1024; // convert from kibibytes to bytes
}
}
}
}
}
if (is_null($memoryTotal) || is_null($memoryFree)) {
return null;
} else {
if ($getPercentage) {
return (100 - ($memoryFree * 100 / $memoryTotal));
} else {
return array(
"total" => $memoryTotal,
"free" => $memoryFree,
);
}
}
}
function getNiceFileSize($bytes, $binaryPrefix=true) {
if ($binaryPrefix) {
$unit=array('B','KiB','MiB','GiB','TiB','PiB');
if ($bytes==0) return '0 ' . $unit[0];
return @round($bytes/pow(1024,($i=floor(log($bytes,1024)))),2) .' '. (isset($unit[$i]) ? $unit[$i] : 'B');
} else {
$unit=array('B','KB','MB','GB','TB','PB');
if ($bytes==0) return '0 ' . $unit[0];
return @round($bytes/pow(1000,($i=floor(log($bytes,1000)))),2) .' '. (isset($unit[$i]) ? $unit[$i] : 'B');
}
}
// Memory usage: 4.55 GiB / 23.91 GiB (19.013557664178%)
$memUsage = getServerMemoryUsage(false);
echo sprintf("Memory usage: %s / %s (%s%%)",
getNiceFileSize($memUsage["total"] - $memUsage["free"]),
getNiceFileSize($memUsage["total"]),
getServerMemoryUsage(true)
);
?>
不需要 getNiceFileSize() 函數。僅用於縮短位元組大小。
注意:如果您需要伺服器負載(CPU 使用率),我也寫了一個不錯的函數來獲取它:https://php.dev.org.tw/manual/en/function.sys-getloadavg.php#118673
以 KB 或 MB 取得記憶體使用量
<?php
function echo_memory_usage() {
$mem_usage = memory_get_usage(true);
if ($mem_usage < 1024)
echo $mem_usage." 位元組";
elseif ($mem_usage < 1048576)
echo round($mem_usage/1024,2)." KB";
else
echo round($mem_usage/1048576,2)." MB";
echo "<br/>";
}
?>
我可以確認此函數會觸發垃圾回收。我有一個腳本在某個時間點超過了 128MB 的記憶體,並以致命錯誤結束。我很困惑,因為該腳本最初處理了一些大檔案,但從那時起的記憶體負載應該是微不足道的,並且錯誤發生在最後。
這些大檔案是在一個專用函數中處理的,我甚至在檔案寫入磁碟後,在該函數內使用 unset() 處理保存檔案的變數。因此,記憶體應該已被清除兩次,第一次是在 unset() 呼叫之後,第二次是在函數結束之後。
為了除錯記憶體使用情況,我在某些點呼叫了 memory_get_usage(true) 並顯示了記憶體分配。只需在腳本中添加一些顯示,記憶體使用量就不會超過 1MB 的額外開銷(在當前檔案大小之上),並且記憶體錯誤消失了。
[danbrown AT php DOT net 編輯:作者的意圖是僅在 PHP 4 < 4.3.2 中使用。]
我想指出的是,雖然 sandeepc at myrealbox dot com 提出的顯示目前記憶體用量的方法不錯,但透過 grep 處理整個程序列表可能不是個好主意。效能更好的方法是只選取我們感興趣的程序。
<?php
$pid = getmypid();
error_log('記憶體用量 (% KB PID ): ' . `ps --pid $pid --no-headers -o%mem,rss,pid`);
?>
的確,效能提升不多,但一點一滴都有幫助。
請注意,`memory_get_usage` 的說明與其預設參數不同!
"`int memory_get_usage ([ bool $real_usage = FALSE ] )`
傳回目前配置給 PHP 腳本的記憶體量(以位元組為單位)。"
預設參數 = `FALSE`
錯誤說明:傳回目前配置給 PHP 腳本的記憶體量(以位元組為單位)。
應該是:傳回 PHP 腳本目前使用的記憶體量(以位元組為單位)。
sandeepc at myrealbox dot com 發布的方法會產生較大的記憶體用量,我猜測它包含了所有 PHP 直譯器/內部程式碼,而不僅僅是正在執行的腳本。
1) 使用 ps 命令
記憶體用量 (% KB PID ): 0.8 12588 25087 -> 約 12MB
2) 使用 memory_get_usage()
int(6041952) -> 約 6MB
有時,我們需要所有記憶體來執行我們的任務,我們會使用 ini_set('memory_limit', -1 ),或我們擁有的最大值。
為了避免伺服器在長時間且消耗大量記憶體的任務中卡住,我寫了這個檢查。這與 memory_get_usage() 的作用不同,但更多。它顯示程序佔用的虛擬記憶體量,以百分比表示。
<?php
function getVirtualMemoryTaken()
{
$pid = getmypid();
$a = `ps -p $pid v | awk 'END{print $9}'`;
return $a*1;
}
?>
它僅適用於 Linux,已在 Ubuntu 14 中測試。
<?php
$a = ' ';
do { $a .= $a . $a; }
while (getVirtualMemoryTaken() < 20 );
?>
[danbrown AT php DOT net 編輯:此函數僅適用於伺服器已安裝必要第三方軟體的 Windows 版本 PHP。]
我無法讓先前的範例正常運作,因此建立了至少對我來說可行的程式碼。敬請享用!
<?php
// 請注意,您需要從 http://www.sysinternals.com/Utilities/PsTools.html 下載 pslist.exe 工具程式
// 這是因為 Win/2000 本身沒有提供工作清單工具程式。
//
function getMemoryUsage() {
// 嘗試使用 PHP 內建函式
if( function_exists('memory_get_usage') ) {
return memory_get_usage();
}
// 嘗試透過 pslist 命令取得 Windows 記憶體使用量
if ( substr(PHP_OS,0,3) == 'WIN') {
$resultRow = 8;
$resultRowItemStartPosition = 34;
$resultRowItemLength = 8;
$output = array();
exec('pslist -m ' . getmypid() , $output);
return trim(substr($output[$resultRow], $resultRowItemStartPosition, $resultRowItemLength)) . ' KB';
}
// 無任何可用的記憶體功能
return '<b style="color: red;">無數值</b>';
}
?>
這是一個適用於 Windows XP/2003 和大多數 UNIX 與 Mac OS X 發行版的函式。
<?php
if( !function_exists('memory_get_usage') )
{
function memory_get_usage()
{
//如果是 Windows 系統
//在 Win XP Pro SP2 上測試過。應該也能在 Win 2003 Server 上運作
//不適用於 2000
//如果您需要它適用於 2000,請參考 http://us2.php.net/manual/en/function.memory-get-usage.php#54642
if ( substr(PHP_OS,0,3) == 'WIN')
{
if ( substr( PHP_OS, 0, 3 ) == 'WIN' )
{
$output = array();
exec( 'tasklist /FI "PID eq ' . getmypid() . '" /FO LIST', $output );
return preg_replace( '/[\D]/', '', $output[5] ) * 1024;
}
}else
{
//現在假設作業系統是 UNIX
//在 Mac OS X 10.4.6 和 Linux Red Hat Enterprise 4 上測試過
//這應該適用於大多數 UNIX 系統
$pid = getmypid();
exec("ps -eo%mem,rss,pid | grep $pid", $output);
$output = explode(" ", $output[0]);
//rss 以 1024 位元組為單位
return $output[1] * 1024;
}
}
}
?>
當您需要取得作業系統時,不要使用 $_SERVER['OS'] 或 $_ENV['OS'],最好使用 PHP_OS 常數!
<?php
if (substr(PHP_OS,0,3)=='WIN') {
// [...]
}
?>
您還可以取得其他值,例如 CYGWIN_NT-5.0、Linux 等…這是取得系統作業系統的最佳方法(任何 Linux 使用者都可以執行「export OS=windows」)