求高人!fgets数据,array_push到一个数组,在memory_get_usage()占用很少的时候,发生了memory exhausted,为什么? 本帖最后由 yifulou 于 2013-01-31 08:09:05 编辑 解决方案 » 免费领取超大流量手机卡,每月29元包185G流量+100分钟通话, 中国电信官方发货 刚看了一个文章,或许可以通过这里开始入手分析:http://blog.csdn.net/21aspnet/article/details/7404059 1、错误信息显示: 在 16M 限定的内存中无法申请一块 4M 的空间(注意是连续内存空间)2、出错前 memory_get_usage 显示已用内存为 13.25M。所以可用的内存只有 16-13.25=2.75 显然是不够了3、fgets($fp, 4096 * 1024); 表示你打算读取 4M 的数据,当然 fgets 函数要先去申请这么大的内存来保存读到的数据注意:这块内存是在 fgets 函数结束时就释放的,当然在释放前要把读到的数据抄写到php的变量中去换句话说,如果你申请到了 4M 内存,并且也读到了 4M 的数据,那么在抄写变量时还需要有 4M 的内存给php变量4、php的函数(内置、自定义)使用同样的方式使用内存:函数结束时释放函数内除静态变量以外的所有局部变量 其实您说的我都能看到,但如果您也照我给的例子测试一次的话,您会发现,string(10) "13,893,632"出现了很多次,即按您说的,早就用了13.25M了,但只是在最后一次提示了exhausted,为什么之前没有提示呢?其次,memory_get_usage()是emalloc的内存,即是实际变量使用的内存吧?但memory_get_usage(true)-memory_get_usage()的内存是什么呢?我看过一些解释,说memory_get_usage(true)包括内存管理器的内存,可难道内存管理器管理一个1M多的数组需要10M以上,即10倍左右的内存?而且,我也尝试过在数组超过1000个元素以后,数组$arr=array()并重新push,那时memory_get_usage(true)是9M多,但我发现,之后,memory_get_usage(true)也并没有被减小,貌似表示,memory_get_usage(true)-memory_get_usage()和管理数组$arr的内存也关系不大,这是为什么呢?现在我怀疑问题发生在内存管理器上,我编译php时候,没有设置内存管理器,用的应该是默认的内存管理器,但我看文档,貌似现在可以编译为别的更好的内存管理器,我正考虑往这方面试试。您认为呢? 也有可能是9M多没释放被当做缓存了,也许算是php的优化机制也说不定,不知道也还是对巨大的memory_get_usage(true)-memory_get_usage()内容很困惑,怎么就耗了这么大呢 自己再把新的想法在这记录一下,以后可以通过研究过php源码再验证一下,目前有这种猜测:1、假设memory_get_usage(true)-memory_get_usage()主要就是数组的管理内存。2、每次memory_get_usage(true)增加和fgets请求的大小一致,或许是因为fgets确实需要分配内存,但使用后不释放,当做下一次fgets的缓存和数组的管理内存,直接使用,或许是避免每次都重新分配内存的一种优化方式吧。当这块内存被占满后,再进行下一次分配,所以之前的很多次提示memory_get_usage(true)已经是13.25M,但fgets时却没有提示,由于他也依然在用之前分配而未释放的这段内存区域。3、即使$arr=null也不减小或许也是同理,虽然不减小,但也不会像之前一样继续增加内存分配,目的也是避免多次重新分配内存。4、由于管理内存和fgets缓存都在用每次预分配的4M,可能会造成缓存和数组管理内存之间产生一定的内存碎片,间接造成memory_get_usage(true)过分的大。对于这种每次都彻底读出一个小文件全部内容的程序,应该用file函数可以得到很大优化这就验证一下4~~ 4验证成功~~代码如下:$arr = array();while(true){ $events = null; flush(); gc_collect_cycles(); var_dump(number_format(memory_get_usage(true))); $events = file("event.txt"); var_dump(number_format(memory_get_usage())); $arr = array_merge($arr, $events);}执行效果如下:。。。string(9) "4,528,496"string(9) "5,767,168"string(9) "4,530,356"string(9) "5,767,168"string(9) "4,532,088"string(9) "5,767,168"string(9) "4,533,880"string(9) "5,767,168"string(9) "4,535,712"string(9) "5,767,168"string(9) "4,537,492"^C最终我ctrl+c停止了,可以看到,memory_get_usage(true)与memory_get_usage()相差很小,确实有很大的优化效果,也验证了,管理内存绝对不会需要10倍多那么离谱之前的memory_get_usage(true)超大很有可能是内存碎片造成。暂时就当个想法吧,以后遇到这种问题先这么解决了~~回头有时间研究一下内存管理器的源码验证一下~~这个结论确实是瞎猜的算是,希望各位有啥新的想法随时来此赐教~~谢谢~~ PHP内部运行机制 高手帮忙给点意见啊 mysql_real_escape_string处理数据的问题 可否在inpu中使用变量? 请教关于require_once的问题. odbc连接Excel2007的问题!!!!!!!!!! 如何重新编译php 如果按指定数值分割字符串? PHP 开发利器 PhpStorm 7 发布 请教个问题 几个php基础但是书上没找到的问题 如何编写不匹配指定单词的正则表达式?
http://blog.csdn.net/21aspnet/article/details/7404059
2、出错前 memory_get_usage 显示已用内存为 13.25M。所以可用的内存只有 16-13.25=2.75
显然是不够了
3、fgets($fp, 4096 * 1024); 表示你打算读取 4M 的数据,当然 fgets 函数要先去申请这么大的内存来保存读到的数据
注意:这块内存是在 fgets 函数结束时就释放的,当然在释放前要把读到的数据抄写到php的变量中去
换句话说,如果你申请到了 4M 内存,并且也读到了 4M 的数据,那么在抄写变量时还需要有 4M 的内存给php变量
4、php的函数(内置、自定义)使用同样的方式使用内存:函数结束时释放函数内除静态变量以外的所有局部变量
其实您说的我都能看到,但如果您也照我给的例子测试一次的话,您会发现,string(10) "13,893,632"出现了很多次,即按您说的,早就用了13.25M了,但只是在最后一次提示了exhausted,为什么之前没有提示呢?
其次,memory_get_usage()是emalloc的内存,即是实际变量使用的内存吧?但memory_get_usage(true)-memory_get_usage()的内存是什么呢?我看过一些解释,说memory_get_usage(true)包括内存管理器的内存,可难道内存管理器管理一个1M多的数组需要10M以上,即10倍左右的内存?
而且,我也尝试过在数组超过1000个元素以后,数组$arr=array()并重新push,那时memory_get_usage(true)是9M多,但我发现,之后,memory_get_usage(true)也并没有被减小,貌似表示,memory_get_usage(true)-memory_get_usage()和管理数组$arr的内存也关系不大,这是为什么呢?现在我怀疑问题发生在内存管理器上,我编译php时候,没有设置内存管理器,用的应该是默认的内存管理器,但我看文档,貌似现在可以编译为别的更好的内存管理器,我正考虑往这方面试试。您认为呢?
也有可能是9M多没释放被当做缓存了,也许算是php的优化机制也说不定,不知道也还是对巨大的memory_get_usage(true)-memory_get_usage()内容很困惑,怎么就耗了这么大呢
1、假设memory_get_usage(true)-memory_get_usage()主要就是数组的管理内存。
2、每次memory_get_usage(true)增加和fgets请求的大小一致,或许是因为fgets确实需要分配内存,但使用后不释放,当做下一次fgets的缓存和数组的管理内存,直接使用,或许是避免每次都重新分配内存的一种优化方式吧。当这块内存被占满后,再进行下一次分配,所以之前的很多次提示memory_get_usage(true)已经是13.25M,但fgets时却没有提示,由于他也依然在用之前分配而未释放的这段内存区域。
3、即使$arr=null也不减小或许也是同理,虽然不减小,但也不会像之前一样继续增加内存分配,目的也是避免多次重新分配内存。4、由于管理内存和fgets缓存都在用每次预分配的4M,可能会造成缓存和数组管理内存之间产生一定的内存碎片,间接造成memory_get_usage(true)过分的大。对于这种每次都彻底读出一个小文件全部内容的程序,应该用file函数可以得到很大优化这就验证一下4~~
$arr = array();
while(true){
$events = null;
flush();
gc_collect_cycles();
var_dump(number_format(memory_get_usage(true)));
$events = file("event.txt");
var_dump(number_format(memory_get_usage()));
$arr = array_merge($arr, $events);
}执行效果如下:
。
。
。
string(9) "4,528,496"
string(9) "5,767,168"
string(9) "4,530,356"
string(9) "5,767,168"
string(9) "4,532,088"
string(9) "5,767,168"
string(9) "4,533,880"
string(9) "5,767,168"
string(9) "4,535,712"
string(9) "5,767,168"
string(9) "4,537,492"
^C最终我ctrl+c停止了,可以看到,memory_get_usage(true)与memory_get_usage()相差很小,确实有很大的优化效果,也验证了,管理内存绝对不会需要10倍多那么离谱之前的memory_get_usage(true)超大很有可能是内存碎片造成。暂时就当个想法吧,以后遇到这种问题先这么解决了~~回头有时间研究一下内存管理器的源码验证一下~~这个结论确实是瞎猜的算是,希望各位有啥新的想法随时来此赐教~~谢谢~~