[原创]unset函数内存分配和销毁问题探秘,及PHP在运行时占用了多少内存的获取。

jackxiang 2008-12-19 19:17 | |
**rvinzhou(周*飞) 14:28:27
波波  请教个问题  你晓得一个php请求  在服务器上占用多少内存  这个有办法查的吗

jackxiang(向东) 14:30:23
$a = memory_get_usage(); Bytes为单位。

也就是当时 PHP 脚本使用的内存(不含 memory_get_usage() 函数本身占用的内存)
由下面的例子可以看出,要想减少内存的占用,可以使用 PHP unset() 函数把不再需要使用的变量删除(下面就是测试真的销毁了没)。类似的还有:PHP mysql_free_result() 函数,可以清空不再需要的查询数据库得到的结果集,这样也能得到更多可用内存。
PHP memory_get_usage()还可以有个参数,$real_usage,其值为布尔值。默认为 FALSE,表示得到的内存使用量不包括该函数(PHP 内存管理器)占用的内存;当设置为 TRUE 时,得到的内存为不包括该函数(PHP 内存管理器)占用的内存。
所以在实际编程中,可以用PHP memory_get_usage()比较各个方法占用内存的高低,来选择使用哪种占用内存小的方法。


<?php
for ( $i = 1; $i < 100; $i++ ) {
$str = str_repeat('01234567', $i);
$a = memory_get_usage();
unset($str);
echo $str;
$b = memory_get_usage();
echo "\n<br />".$i.': '.($b - $a).' Bytes.';
}
?>




<br />10: 0 Bytes.
<br />11: 0 Bytes.
<br />12: 0 Bytes.
<br />13: 0 Bytes.
<br />14: 0 Bytes.
<br />15: 0 Bytes.
<br />16: 0 Bytes.
<br />17: -148 Bytes.
<br />18: -156 Bytes.
<br />19: -164 Bytes.
<br />20: -172 Bytes.
<br />21: -180 Bytes


据我的了解,unset()是用来销毁指定的变量、释放内存
经过以上代码的测试,变量确实没有值了,物理内存也释放了。
但是我在测试的我spider程序时,电脑运行变的很慢。
每一次测试后,对电脑的运行速度的影响就越大。
我的spider程序中,用到了大量的unset。
查看了一下物理内存的使用,spider程序运行结束后,会下降到很低,CPU使用率也下降到4%左右。
实在没办法就重启了一下apache服务器,系统立刻恢复正常。
再经过测试,发现每运行一次php程序(有unset操作的),虚拟内存就增加一点,运行结束后,不会下降,
而且全是httpd.exe所占用的。
所以我想,unset的操作,并没有销毁变量,只是把它从物理内存转移到虚拟内存了。
apache服务器不停止,它也一直不释放,只增不减。
这是我的个人猜想,如果有人遇到这样的问题的话,希望可以讨论一下,也希望高手指导一下。
下面是测试程序:
<?php
for ( $i = 1; $i < 100000; $i++ ) {
$str = str_repeat('pgpgpgpgpgpg', 1000);
unset($str);
}
?>
ps:虚拟内存的查看可以在任务管理器中,点查看---选择列--在虚拟内存上打勾
这样就可以监视它们的使用情况了!
但是感觉不对,你这都是在for循环内部,而且就是你unset($str)了。但$a或者$i都是占用内存空间的。
PHP的垃圾回收机制相类似, 对于全局作用域的变量, unset只是告诉ZE, 这个变量可以被回收,但是具体什么时候回收,那确是有ZE决定的。 一般来说是会在RSHUTDOWN函数中进行。
你的问题挺好。呵呵!

转载:
首先要强调的一点是unset在php中已经不再是一个函数了,既然不是函数,那么就没有了返回值,所以用的时候不能够用unset的返回值来做判断。
其次,在函数中,unset只能销毁局部变量,并不能销毁全局变量,来看下手册的一个例子
    <?php
    function destroy_foo() {
    global $foo;
    unset($foo);
    }

    $foo = ‘bar’;
    destroy_foo();
    echo $foo;
    ?>

返回的结果为
    bar

为什么会这样呢?原因就是unset在函数中只能销毁局部变量。如果在程序中需要用到销毁全局变量的应该如何做呢?也很简单,用$GLOBALS数组来实现。看下面的例子:
    <?php
    function foo() {
    unset($GLOBALS['bar']);
    }

    $bar = “something”;
    foo();
    var_dump($bar);
    ?>

这样程序就会返回NULL。
首先,unset不能释放占用的内存资源,你会问:
如果只是打断了指针,那变量在内存中的存储不就是没有销毁?
还是仅仅是引用的时候才这样?
如果都这样不是很浪费资源?

应该不存在浪费资源一说。php也有类似java的垃圾回收机制!
当给一个变量赋值(或者相类似的操作),内存会开辟一个空间存储,这时候会产生两个重要的概念,一个是“内存的地址”,一个是“地址内的内容”。
unset打断了变量与地址间的联系。而php会自动检测内存地址里的数据是否完全没有跟其它变量产生联系,在确定没有的情况下会回收内存。
所以要回收内存,那就要把所有的联系打断。
是打断指针的,因为PHP的引用不是C语言中的指针!C语言的指针可以做到注销变量内容,只要取得内存地址的内容就可以注销变量内容了!不过PHP不行!

结合上面两篇文章,得出结论:对于全局的变量,我们实际是没有销毁的事实,unset其实根本没有销毁掉变量本身,估计就是通过修改地址等虚拟手段让其无法访问到而已,但要是通过它自己的内存机制还是可以访问的,我们无法了解它的内存机制,觉得是被销毁罢了。。。。

作者:jackxiang@向东博客 专注WEB应用 构架之美 --- 构架之美,在于尽态极妍 | 应用之美,在于药到病除
地址:https://jackxiang.com/post/1520/
版权所有。转载时必须以链接形式注明作者和原始出处及本声明!


最后编辑: jackxiang 编辑于2012-8-27 14:35
评论列表
发表评论

昵称

网址

电邮

打开HTML 打开UBB 打开表情 隐藏 记住我 [登入] [注册]