php memory_get_usage(true)和top %MEM的区别

7
我有一个使用AWS Dynamo PHP API编写的PHP脚本,它运行一个长循环,在其中从dynamo拉取大量数据,然后处理数据。
当我使用“top”观察进程时,可以看到“php”进程使用的内存使用情况。
在我的脚本循环中,我打印了memory_get_usage(true)的结果。
但在我的测试中,这两个值非常不相似...
它们应该是相似的吗?如果不是,为什么?
在我的测试中,我有一台带有1.7GB RAM的服务器,并将php.ini的memory_limit设置为64M。我还在我的脚本开头调用了gc_enable(),并在每次循环调用之间调用gc_collect_cycles(),希望强制进行垃圾回收。
当我使用“top”观察我的php脚本时,可以看到%MEM不断上升,直到最终超过95%,Linux会杀死php进程,我从“dmesg”中得知。当我查看循环的每次迭代的打印输出时,由memory_get_usage(true)报告的内存使用情况从未超过50MB。
Linux认为脚本使用了近1.7GB内存,而php只认为使用了50MB!
出了什么问题?
即使脚本存在内存泄漏,我也不明白为什么memory_get_usage(true)不计算内存使用情况...

更新

在花费一些时间注释循环内部运行的各个部分之后,我发现如果删除以下代码:
class cMyClass {
    public static function static_cmp_fn(&$a, &$b) {
        if ($a['att'] == $b['att']) { return 0; }
        $ret = ($a['att'] < $b['att']) ? -1 : +1;
        return $ret;
    }
    function DoProcessing(){
        $sort_fn = array("cMyClass", "static_cmp_fn");
        usort($this->m_dictToSort, $sort_fn); 
        unset($sort_fn);
    }

}

PHP不会占用所有系统内存。看起来usort在泄露内存,我不知道为什么。我不明白的是为什么PHP报告使用内存的信息有误...

有什么想法吗?


显示 memory_get_peak_usage() 的输出。 - meze
当我将这个添加到我的日志记录中时,每次循环迭代它会打印出大约75MB的内容,与top报告的PHP使用的1.7GB系统内存的95%完全不同。 - sungiant
那么,你的PHP版本或使用的扩展存在问题。PHP永远不会让用户分配超过memory_limit的内存。 - meze
你的 static_cmp_fn 函数里面是什么内容? - meze
1个回答

1
在我的循环中运行处理的各个部分进行注释一段时间后,我发现如果删除以下代码:
$sort_fn = array("cMyClass", "static_cmp_fn");
usort($this->m_dictToSort, $sort_fn); 
php永远不会占用全部系统内存。在我看来,usort正在泄漏内存,但我不知道为什么。
显然是这样的。请参考手册:

http://php.net/manual/en/function.usort.php

这里有几个例子提倡使用'create_function'进行排序,因为usort的限制很诱人。但是要注意这种方法--在排序过程结束时创建的函数将不会被释放,这会导致内存泄漏。因此,这种方法可能永远不应该被使用。

array()方法似乎做了类似的事情。你可以声明一个包装函数来调用你的方法外部,也许?

更新

试图构建一个小的测试用例来看看会发生什么。到目前为止,我无法重现泄漏;也许有关static_cmp_fn()做什么以及m_dictToSort如何结构的更多数据。简单的比较不会触发任何奇怪的东西。在循环内分配字符串、数组或对象也不会触发任何奇怪的东西。垃圾收集器会杀死它们,内存保持低水平。

我会通过调用另一个根本不排序或者只进行非常基本排序的函数来进一步限制问题,以查看问题是否在usort中使用其可调用对象时出现了一些奇怪的东西,正如我所想的那样(似乎它没有,我错了),或者比较函数内部发生了一些奇怪的事情。


我对此感到困惑,也尝试过添加unset($sort_fn),但没有成功。文档中没有任何提示表明传递一个提供类名和静态函数名称的数组与使用PHP的“create_function”函数动态创建函数是相同的。 - sungiant
在array()中的回调函数与create_function不同。而且,如果没有证据,引用旧评论时要小心。 - meze
除了查看PHP代码,我们无法知道usort()对数组执行的操作。但你是对的,我会进行一些实验。 - LSerni
usort() 的实现从第 635 行开始。祝好运:http://pastebin.ca/2238002 - mishmash

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接