以 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
?>
注意,千字节、兆字节等的官方 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
// 返回已用内存(以百分比(不带百分号)或以字节为单位的空闲和总内存)
function getServerMemoryUsage($getPercentage=true)
{
$memoryTotal = null;
$memoryFree = null;
if (stristr(PHP_OS, "win")) {
// 获取总物理内存(以字节为单位)
$cmd = "wmic ComputerSystem get TotalPhysicalMemory";
@exec($cmd, $outputTotalPhysicalMemory);
// 获取空闲物理内存(以 KiB 为单位!)
$cmd = "wmic OS get FreePhysicalMemory";
@exec($cmd, $outputFreePhysicalMemory);
if ($outputTotalPhysicalMemory && $outputFreePhysicalMemory) {
// 查找总值
foreach ($outputTotalPhysicalMemory as $line) {
if ($line && preg_match("/^[0-9]+\$/", $line)) {
$memoryTotal = $line;
break;
}
}
// 查找空闲值
foreach ($outputFreePhysicalMemory as $line) {
if ($line && preg_match("/^[0-9]+\$/", $line)) {
$memoryFree = $line;
$memoryFree *= 1024; // 从 KiB 转换为字节
break;
}
}
}
}
else
{
if (is_readable("/proc/meminfo"))
{
$stats = @file_get_contents("/proc/meminfo");
if ($stats !== false) {
// 分隔行
$stats = str_replace(array("\r\n", "\n\r", "\r"), "\n", $stats);
$stats = explode("\n", $stats);
// 分隔值并查找总内存和空闲内存的正确行
foreach ($stats as $statLine) {
$statLineData = explode(":", trim($statLine));
//
// 提取大小(TODO:似乎总内存和空闲内存的两个值始终具有单位“kB”。这是正确的吗?
//
// 总内存
if (count($statLineData) == 2 && trim($statLineData[0]) == "MemTotal") {
$memoryTotal = trim($statLineData[1]);
$memoryTotal = explode(" ", $memoryTotal);
$memoryTotal = $memoryTotal[0];
$memoryTotal *= 1024; // 从 KiB 转换为字节
}
// 空闲内存
if (count($statLineData) == 2 && trim($statLineData[0]) == "MemFree") {
$memoryFree = trim($statLineData[1]);
$memoryFree = explode(" ", $memoryFree);
$memoryFree = $memoryFree[0];
$memoryFree *= 1024; // 从 KiB 转换为字节
}
}
}
}
}
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');
}
}
// 内存使用情况: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.net/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)." 千字节";
else
echo round($mem_usage/1048576,2)." 兆字节";
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 命令
MEMORY USAGE (% 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")
Win XP / 2003 替代脚本也可以通过一些小的修改在 Windows 2000 上运行。
请注意,您需要来自 http://www.sysinternals.com/Utilities/PsTools.html 的 pslist.exe 实用程序,因为 win/2000 本身没有提供任务列表实用程序。
<?php
function getMemUsage()
{
if (function_exists('memory_get_usage'))
{
return memory_get_usage();
}
else if ( substr(PHP_OS,0,3) == 'WIN')
{
// Windows 2000 workaround
$output = array();
exec('pslist ' . getmypid() , $output);
return trim(substr($output[8],38,10));
}
else
{
return '<b style="color: red;">no value</b>';
}
}
?>
解决 Windows 系统下的 memory_get_usage 问题
测试操作系统:Windows XP
服务器:Apache
PHP 必须以 CGI 的方式加载,才能通过进程 ID ( getmypid() ) 和 tasklist.exe 等命令行工具正确获取内存使用情况。
以 CGI 方式加载的 PHP 拥有自己的 PID,而不是常量 Apache PID,这样就可以获得独立于 Apache 内存使用情况的真实内存大小。
在 Apache 的 httpd.conf 中配置
1. 注释掉类似这样的行
LoadModule php4_module "/usr/local/php/sapi/php4apache.dll"
或者
LoadModule php5_module "/usr/local/php5/php5apache.dll"
2. 添加以下内容并编辑你的 php 路径
<Directory "z:/usr/local/php">
Options ExecCGI
</Directory>
ScriptAlias "/__php_dir__/" "z:/usr/local/php/"
Action application/x-httpd-php "/__php_dir__/php.exe"
3. 重启 Apache
使用以下 PHP 代码
<?php
/**
* Windows 系统的 memory_get_usage() 函数,编译时没有使用 --enable-memory-limit 选项
* PHP 必须以 CGI 方式加载
* 来自 miteigi nemoto 的问候
* @return string
*/
function memory_get_usage_by_tasklist()
{
$output = array();
exec( 'tasklist ', $output );
foreach ($output as $value)
{
$ex=explode(" ",$value);
$count_ex=count($ex);
if (eregi(" ".getmypid()." Console",$value))
{
$memory_size=$ex[$count_ex-2]." Kb";
return $memory_size;
}
}
}
echo memory_get_usage_by_tasklist();
?>
这里各种 memory_get_usage 的替代方案似乎在 Mac OS X 10.4 (Intel) 上不起作用。
我让它按以下方式工作...
<?php
function memory_get_usage()
{
$pid = getmypid();
exec("ps -o rss -p $pid", $output);
return $output[1] *1024;
}
?>