获取 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("内存使用情况:%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('MEMORY USAGE (% 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”)。